diff --git a/backend/file.go b/backend/file.go index 9f4dd59..e2c9444 100644 --- a/backend/file.go +++ b/backend/file.go @@ -4,11 +4,11 @@ import ( "encoding/json" "errors" "io/ioutil" + "log" "os" pathpkg "path" "sync" "time" - "log" ) type File struct { diff --git a/server.go b/server.go index d26b11a..66a7e6a 100644 --- a/server.go +++ b/server.go @@ -1,19 +1,14 @@ package main import ( - "encoding/json" "flag" - "fmt" "log" "math/rand" - "strings" "time" "github.com/GeertJohan/go.rice" - "github.com/qiangxue/fasthttp-routing" - "github.com/valyala/fasthttp" "github.com/vharitonsky/iniflags" - bk "github.com/xtrafrancyz/golish/backend" + "github.com/xtrafrancyz/golish/backend" ) var Config struct { @@ -35,9 +30,6 @@ var Config struct { filePath string } -var backend bk.Backend -var adminFiles *rice.Box - func main() { rand.Seed(time.Now().UTC().UnixNano()) @@ -55,11 +47,12 @@ func main() { iniflags.Parse() - var err error + var err error = nil + var storage backend.Backend = nil if Config.backend == "mysql" { - backend, err = bk.NewMysql(Config.slugLength, Config.mysqlHost, Config.mysqlUser, Config.mysqlPassword, Config.mysqlDatabase) + storage, err = backend.NewMysql(Config.slugLength, Config.mysqlHost, Config.mysqlUser, Config.mysqlPassword, Config.mysqlDatabase) } else if Config.backend == "file" { - backend, err = bk.NewFile(Config.slugLength, Config.filePath) + storage, err = backend.NewFile(Config.slugLength, Config.filePath) } else { log.Fatalf("backend must be 'mysql' or 'file'") return @@ -69,140 +62,9 @@ func main() { return } - adminFiles = rice.MustFindBox("admin") - adminFiles.HTTPBox() - - router := routing.New() - router.Get("/", handleRoot) - router.Get("/", handleSlug) - adminGroup := router.Group("/@"+Config.adminPath, addACAO) - adminGroup.Get("/list", handleList) - adminGroup.Post("/create", handleCreate) - adminGroup.Post("/delete", handleDelete) - adminGroup.Post("/edit", handleEdit) - adminGroup.Get("/", handleAdminRoot) - - server := &fasthttp.Server{ - Handler: router.HandleRequest, - ReduceMemoryUsage: true, - } - - log.Printf("Starting server on http://%s:%d", Config.host, Config.port) - err = server.ListenAndServe(fmt.Sprintf("%s:%d", Config.host, Config.port)) - - if err != nil { - log.Fatalf("error in fasthttp server: %s", err) + web := &web{ + backend: storage, + adminFiles: rice.MustFindBox("admin"), } -} - -func addACAO(c *routing.Context) error { - c.Response.Header.Set("Access-Control-Allow-Origin", "*") - return nil -} - -func handleRoot(c *routing.Context) error { - if Config.defaultRedirect != "" { - c.Redirect(Config.defaultRedirect, fasthttp.StatusFound) - } else { - c.NotFound() - } - return nil -} - -func handleSlug(c *routing.Context) error { - log.Print(string(c.URI().Path())) - full := backend.TryClickLink(c.Param("slug")) - - if full != nil { - c.Redirect(full.Url, fasthttp.StatusFound) - } else { - c.NotFound() - } - - return nil -} - -func handleAdminRoot(c *routing.Context) error { - path := "/" + c.Param("file") - if path == "/" { - path = "/index.html" - } - log.Print("{admin}" + path) - bytes, err := adminFiles.Bytes(path) - if err != nil { - c.NotFound() - } else { - if strings.HasSuffix(path, ".html") { - c.Response.Header.Set("Content-Type", "text/html") - } else if strings.HasSuffix(path, ".css") { - c.Response.Header.Set("Content-Type", "text/css") - } else if strings.HasSuffix(path, ".js") { - c.Response.Header.Set("Content-Type", "application/javascript") - } else if strings.HasSuffix(path, ".png") { - c.Response.Header.Set("Content-Type", "image/png") - } - c.SetStatusCode(fasthttp.StatusOK) - c.Write(bytes) - } - return nil -} - -func handleList(c *routing.Context) error { - log.Print("{admin}/list") - links := backend.GetAllLinks() - marshaled, _ := json.Marshal(links) - c.Response.Header.Set("Content-Type", "application/json") - c.Write(marshaled) - return nil -} - -func handleCreate(c *routing.Context) error { - url := c.PostArgs().Peek("url") - log.Printf("{admin}/create (url=%s)", url) - if len(url) == 0 { - c.SetStatusCode(fasthttp.StatusBadRequest) - } else { - var link *bk.Link - var err error - slug := c.PostArgs().Peek("slug") - if len(slug) == 0 { - link, err = backend.Create(string(url)) - } else { - link, err = backend.CreateCustom(string(slug), string(url)) - } - var marshaled []byte - if err != nil { - marshaled, _ = json.Marshal(OperationError{ - Error: true, - Message: err.Error(), - }) - } else { - marshaled, _ = json.Marshal(link) - } - c.Response.Header.Set("Content-Type", "application/json") - c.Write(marshaled) - } - return nil -} - -func handleDelete(c *routing.Context) error { - slug := c.PostArgs().Peek("slug") - log.Printf("{admin}/delete (slug=%s)", slug) - backend.Delete(string(slug)) - c.SetStatusCode(fasthttp.StatusOK) - return nil -} - -func handleEdit(c *routing.Context) error { - slug := c.PostArgs().Peek("slug") - url := c.PostArgs().Peek("url") - log.Printf("{admin}/edit (slug=%s, url=%s)", slug, url) - backend.Edit(string(slug), string(url)) - c.SetStatusCode(fasthttp.StatusOK) - return nil -} - -type OperationError struct { - Error bool `json:"error"` - Message string `json:"message"` + web.run() } diff --git a/web.go b/web.go new file mode 100644 index 0000000..5aefd1e --- /dev/null +++ b/web.go @@ -0,0 +1,154 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "strings" + + "github.com/GeertJohan/go.rice" + "github.com/qiangxue/fasthttp-routing" + "github.com/valyala/fasthttp" + "github.com/xtrafrancyz/golish/backend" +) + +type web struct { + backend backend.Backend + adminFiles *rice.Box +} + +func (w *web) run() { + router := routing.New() + router.Get("/", w.handleRoot) + router.Get("/", w.handleSlug) + adminGroup := router.Group("/@"+Config.adminPath, w.addACAO) + adminGroup.Get("/list", w.handleList) + adminGroup.Post("/create", w.handleCreate) + adminGroup.Post("/delete", w.handleDelete) + adminGroup.Post("/edit", w.handleEdit) + adminGroup.Get("/", w.handleAdminRoot) + + server := &fasthttp.Server{ + Handler: router.HandleRequest, + ReduceMemoryUsage: true, + } + + log.Printf("Starting server on http://%s:%d", Config.host, Config.port) + err := server.ListenAndServe(fmt.Sprintf("%s:%d", Config.host, Config.port)) + + if err != nil { + log.Fatalf("error in fasthttp server: %s", err) + } +} + +func (w *web) addACAO(c *routing.Context) error { + c.Response.Header.Set("Access-Control-Allow-Origin", "*") + return nil +} + +func (w *web) handleRoot(c *routing.Context) error { + if Config.defaultRedirect != "" { + c.Redirect(Config.defaultRedirect, fasthttp.StatusFound) + } else { + c.NotFound() + } + return nil +} + +func (w *web) handleSlug(c *routing.Context) error { + log.Print(string(c.URI().Path())) + full := w.backend.TryClickLink(c.Param("slug")) + + if full != nil { + c.Redirect(full.Url, fasthttp.StatusFound) + } else { + c.NotFound() + } + + return nil +} + +func (w *web) handleAdminRoot(c *routing.Context) error { + path := "/" + c.Param("file") + if path == "/" { + path = "/index.html" + } + log.Print("{admin}" + path) + bytes, err := w.adminFiles.Bytes(path) + if err != nil { + c.NotFound() + } else { + if strings.HasSuffix(path, ".html") { + c.Response.Header.Set("Content-Type", "text/html") + } else if strings.HasSuffix(path, ".css") { + c.Response.Header.Set("Content-Type", "text/css") + } else if strings.HasSuffix(path, ".js") { + c.Response.Header.Set("Content-Type", "application/javascript") + } else if strings.HasSuffix(path, ".png") { + c.Response.Header.Set("Content-Type", "image/png") + } + c.SetStatusCode(fasthttp.StatusOK) + c.Write(bytes) + } + return nil +} + +func (w *web) handleList(c *routing.Context) error { + log.Print("{admin}/list") + links := w.backend.GetAllLinks() + marshaled, _ := json.Marshal(links) + c.Response.Header.Set("Content-Type", "application/json") + c.Write(marshaled) + return nil +} + +func (w *web) handleCreate(c *routing.Context) error { + url := c.PostArgs().Peek("url") + log.Printf("{admin}/create (url=%s)", url) + if len(url) == 0 { + c.SetStatusCode(fasthttp.StatusBadRequest) + } else { + var link *backend.Link = nil + var err error = nil + slug := c.PostArgs().Peek("slug") + if len(slug) == 0 { + link, err = w.backend.Create(string(url)) + } else { + link, err = w.backend.CreateCustom(string(slug), string(url)) + } + var marshaled []byte + if err != nil { + marshaled, _ = json.Marshal(OperationError{ + Error: true, + Message: err.Error(), + }) + } else { + marshaled, _ = json.Marshal(link) + } + c.Response.Header.Set("Content-Type", "application/json") + c.Write(marshaled) + } + return nil +} + +func (w *web) handleDelete(c *routing.Context) error { + slug := c.PostArgs().Peek("slug") + log.Printf("{admin}/delete (slug=%s)", slug) + w.backend.Delete(string(slug)) + c.SetStatusCode(fasthttp.StatusOK) + return nil +} + +func (w *web) handleEdit(c *routing.Context) error { + slug := c.PostArgs().Peek("slug") + url := c.PostArgs().Peek("url") + log.Printf("{admin}/edit (slug=%s, url=%s)", slug, url) + w.backend.Edit(string(slug), string(url)) + c.SetStatusCode(fasthttp.StatusOK) + return nil +} + +type OperationError struct { + Error bool `json:"error"` + Message string `json:"message"` +}