refactoring. remove global state, use new logging, config functions

This commit is contained in:
2018-06-17 16:15:58 +02:00
parent d091398f05
commit 75197310bf
24 changed files with 295 additions and 476 deletions

View File

@@ -1,101 +0,0 @@
package conf
import (
"os"
"sort"
"fornaxian.com/pixeldrain-web/log"
"github.com/spf13/viper"
)
var vi *viper.Viper
var defaultConfig = `# Pixeldrain Web UI server configuration
api_url_external = "https://sia.pixeldrain.com/api" # Used in the web browser, should be a full URL. Not ending with a slash
api_url_internal = "http://127.0.0.1:8080/api" # Used for internal API requests to the pixeldrain server, not visible to users
static_resource_dir = "res/static"
template_dir = "res/template"
debug_mode = false`
// Init reads the config file
func Init() {
if vi != nil {
log.Error("Config already initialized, can't ititialize again")
return
}
vi = viper.New()
vi.SetConfigType("toml")
vi.SetConfigName("pdwebconf")
vi.AddConfigPath(".")
vi.AddConfigPath("./conf")
vi.AddConfigPath("/etc")
vi.AddConfigPath("/usr/local/etc")
vi.SetDefault("api_url_external", "/api")
vi.SetDefault("api_url_internal", "http://127.0.0.1:8080/api")
vi.SetDefault("static_resource_dir", "./res/static")
vi.SetDefault("template_dir", "./res/template")
vi.SetDefault("debug_mode", false)
err := vi.ReadInConfig()
if err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
writeCfg()
log.Warn("Generated config file \"pdwebconf.toml\", please edit and run again.")
os.Exit(0)
} else if _, ok := err.(viper.ConfigParseError); ok {
log.Error("Could not parse config file: ", err)
} else {
log.Error("Unknown error occured while reading config file: ", err)
}
}
log.Info("Web UI configuration:")
keys := vi.AllKeys()
numKeys := len(keys)
sort.Strings(keys)
for i, v := range keys {
if i == numKeys-1 {
log.Info("└%21s: %v", v, vi.Get(v))
} else {
log.Info("├%21s: %v", v, vi.Get(v))
}
}
if DebugMode() {
log.SetLogLevel(4)
} else {
log.SetLogLevel(3)
}
}
func writeCfg() {
file, err := os.Create("pdwebconf.toml")
if err != nil {
log.Error("Could not create config file: ", err)
}
file.WriteString(defaultConfig)
file.Close()
}
func ApiUrlExternal() string {
return vi.GetString("api_url_external")
}
func ApiUrlInternal() string {
return vi.GetString("api_url_internal")
}
func StaticResourceDir() string {
return vi.GetString("static_resource_dir")
}
func TemplateDir() string {
return vi.GetString("template_dir")
}
func DebugMode() bool {
return vi.GetBool("debug_mode")
}

17
init/conf/config.go Normal file
View File

@@ -0,0 +1,17 @@
package conf
type PixelWebConfig struct {
APIURLExternal string `toml:"api_url_external"`
APIURLInternal string `toml:"api_url_internal"`
StaticResourceDir string `toml:"static_resource_dir"`
TemplateDir string `toml:"template_dir"`
DebugMode bool `toml:"debug_mode"`
}
const DefaultConfig = `# Pixeldrain Web UI server configuration
api_url_external = "https://sia.pixeldrain.com/api" # Used in the web browser, should be a full URL. Not ending with a slash
api_url_internal = "http://127.0.0.1:8080/api" # Used for internal API requests to the pixeldrain server, not visible to users
static_resource_dir = "res/static"
template_dir = "res/template"
debug_mode = false`

View File

@@ -1,36 +1,31 @@
package init
import (
"net/http"
"os"
"fornaxian.com/pixeldrain-web/conf"
"fornaxian.com/pixeldrain-web/log"
"fornaxian.com/pixeldrain-web/init/conf"
"fornaxian.com/pixeldrain-web/webcontroller"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/Fornaxian/config"
"github.com/Fornaxian/log"
"github.com/julienschmidt/httprouter"
)
// Init initializes the Pixeldrain Web UI controllers
func Init(r *httprouter.Router, prefix string) {
log.Init()
log.Info("Starting web UI server (PID %v)", os.Getpid())
conf.Init()
templates.ParseTemplates()
var webconf = &conf.PixelWebConfig{}
var _, err = config.New(
conf.DefaultConfig,
"",
"pdwebconf.toml",
webconf,
true,
)
if err != nil {
log.Error("Failed to load config file: %s", err)
os.Exit(1)
}
// Serve static files
r.ServeFiles(prefix+"/res/*filepath", http.Dir(conf.StaticResourceDir()+"/res"))
r.GET(prefix+"/", webcontroller.ServeHome)
r.GET(prefix+"/favicon.ico", webcontroller.ServeFavicon)
r.GET(prefix+"/global.css", webcontroller.GlobalCSSHandler)
r.GET(prefix+"/api", webcontroller.ServeAPIDoc)
r.GET(prefix+"/history", webcontroller.ServeHistory)
r.GET(prefix+"/u/:id", webcontroller.ServeFileViewer)
r.GET(prefix+"/u/:id/preview", webcontroller.ServeFilePreview)
r.GET(prefix+"/l/:id", webcontroller.ServeListViewer)
r.GET(prefix+"/t", webcontroller.ServePaste)
r.NotFound = http.HandlerFunc(webcontroller.ServeNotFound)
webcontroller.New(r, prefix, webconf)
}

View File

@@ -1,97 +0,0 @@
package log
import (
"fmt"
"log"
"os"
"runtime"
"runtime/debug"
)
var logger *log.Logger
const (
LEVEL_DEBUG = 4
LEVEL_INFO = 3
LEVEL_WARNING = 2
LEVEL_ERROR = 1
)
var logLevel = LEVEL_DEBUG
// Init initializes the logger
func Init() {
logger = log.New(os.Stdout, "pdweb ", log.LUTC)
}
// SetLogLevel set the loggin verbosity. 0 is lowest (log nothing at all), 4 is
// highest (log all debug messages)
func SetLogLevel(level int) {
if level < 0 || level > 4 {
Error("Invalid log level %v", level)
return
}
logLevel = level
}
// Debug logs a debug message
func Debug(msgFmt string, v ...interface{}) {
if logLevel < LEVEL_DEBUG {
return
}
if len(v) == 0 {
print("DBG", msgFmt)
} else {
print("DBG", msgFmt, v...)
}
}
// Info logs an info message
func Info(msgFmt string, v ...interface{}) {
if logLevel < LEVEL_INFO {
return
}
if len(v) == 0 {
print("INF", msgFmt)
} else {
print("INF", msgFmt, v...)
}
}
// Warn logs a warning message
func Warn(msgFmt string, v ...interface{}) {
if logLevel < LEVEL_WARNING {
return
}
if len(v) == 0 {
print("WRN", msgFmt)
} else {
print("WRN", msgFmt, v...)
}
}
// Error logs an error message
func Error(msgFmt string, v ...interface{}) {
if logLevel < LEVEL_ERROR {
return
}
if len(v) == 0 {
print("ERR", msgFmt)
} else {
print("ERR", msgFmt, v...)
}
debug.PrintStack()
}
func print(lvl string, msgFmt string, v ...interface{}) {
_, fn, line, _ := runtime.Caller(2)
msg := fmt.Sprintf("[%s] …%s:%-3d %s", lvl, string(fn[len(fn)-20:]), line, msgFmt)
if len(v) == 0 {
logger.Println(msg)
} else {
logger.Printf(msg, v...)
}
}

View File

@@ -4,8 +4,8 @@ import (
"net/http"
web "fornaxian.com/pixeldrain-web/init"
"fornaxian.com/pixeldrain-web/log"
"github.com/Fornaxian/log"
"github.com/julienschmidt/httprouter"
)

View File

@@ -4,14 +4,13 @@ import (
"encoding/json"
"io"
"fornaxian.com/pixeldrain-web/conf"
"fornaxian.com/pixeldrain-web/log"
"github.com/Fornaxian/log"
)
// GetFile makes a file download request and returns a readcloser. Don't forget
// to close it!
func GetFile(id string) (io.ReadCloser, error) {
return getRaw(conf.ApiUrlInternal() + "/file/" + id)
func (p *PixelAPI) GetFile(id string) (io.ReadCloser, error) {
return getRaw(p.apiEndpoint + "/file/" + id)
}
// FileInfo File information object from the pixeldrain API
@@ -30,8 +29,8 @@ type FileInfo struct {
}
// GetFileInfo gets the FileInfo from the pixeldrain API
func GetFileInfo(id string) *FileInfo {
body, err := getString(conf.ApiUrlInternal() + "/file/" + id + "/info")
func (p *PixelAPI) GetFileInfo(id string) *FileInfo {
body, err := getString(p.apiEndpoint + "/file/" + id + "/info")
if err != nil {
log.Error("req failed: %v", err)

View File

@@ -2,8 +2,6 @@ package pixelapi
import (
"encoding/json"
"fornaxian.com/pixeldrain-web/conf"
)
// API error constants
@@ -34,9 +32,9 @@ type ListFile struct {
// GetList get a List from the pixeldrain API. Errors will be available through
// List.Error. Standard error checks apply.
func GetList(id string) *List {
func (p *PixelAPI) GetList(id string) *List {
var list = &List{}
body, err := getString(conf.ApiUrlInternal() + "/list/" + id)
body, err := getString(p.apiEndpoint + "/list/" + id)
if err != nil {
list.Error = errorResponseFromError(err)
return list

9
pixelapi/pixelapi.go Normal file
View File

@@ -0,0 +1,9 @@
package pixelapi
type PixelAPI struct {
apiEndpoint string
}
func New(apiEndpoint string) *PixelAPI {
return &PixelAPI{apiEndpoint}
}

View File

@@ -156,7 +156,6 @@
</p>
<ul>
<li>Zip explorer</li>
<li>Text file viewer (yes, you can upload text but not view it yet)</li>
<li>Some video formats (mime type detection is not complete)</li>
<li>Registration / Login system</li>
<li>Bandwidth Tracker</li>

View File

@@ -1,18 +0,0 @@
package webcontroller
import (
"net/http"
"fornaxian.com/pixeldrain-web/log"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/julienschmidt/httprouter"
)
// ServeAPIDoc serves the API docuementation
func ServeAPIDoc(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
err := templates.Get().ExecuteTemplate(w, "apidoc", nil)
if err != nil {
log.Error("Error executing template apidoc: %s", err)
}
}

View File

@@ -1,14 +0,0 @@
package webcontroller
import (
"net/http"
"github.com/julienschmidt/httprouter"
"fornaxian.com/pixeldrain-web/conf"
)
// ServeFavicon yes we need a controller for this
func ServeFavicon(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
http.ServeFile(w, r, conf.StaticResourceDir()+"favicon.ico")
}

View File

@@ -10,7 +10,6 @@ import (
"path/filepath"
"strings"
"fornaxian.com/pixeldrain-web/conf"
"fornaxian.com/pixeldrain-web/pixelapi"
"github.com/Fornaxian/log"
@@ -19,19 +18,22 @@ import (
)
// ServeFilePreview controller for GET /u/:id/preview
func ServeFilePreview(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
func (wc *WebController) serveFilePreview(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
if p.ByName("id") == "demo" {
ServeFilePreviewDemo(w) // Required for a-ads.com quality check
serveFilePreviewDemo(w) // Required for a-ads.com quality check
return
}
inf := pixelapi.GetFileInfo(p.ByName("id")) // TODO: Error handling
inf := wc.api.GetFileInfo(p.ByName("id")) // TODO: Error handling
if inf == nil {
ServeNotFound(w, r)
wc.serveNotFound(w, r)
return
}
var fp FilePreview
var fp = FilePreview{
APIURL: wc.conf.APIURLExternal,
PixelAPI: wc.api,
}
io.WriteString(w, fp.Run(inf))
}
@@ -39,12 +41,15 @@ type FilePreview struct {
FileInfo *pixelapi.FileInfo
FileURL string
DownloadURL string
APIURL string
PixelAPI *pixelapi.PixelAPI
}
func (f FilePreview) Run(inf *pixelapi.FileInfo) string {
f.FileInfo = inf
f.FileURL = conf.ApiUrlExternal() + "/file/" + f.FileInfo.ID
f.DownloadURL = conf.ApiUrlExternal() + "/file/" + f.FileInfo.ID + "/download"
f.FileURL = f.APIURL + "/file/" + f.FileInfo.ID
f.DownloadURL = f.APIURL + "/file/" + f.FileInfo.ID + "/download"
if strings.HasPrefix(f.FileInfo.MimeType, "image") {
return f.image()
@@ -139,7 +144,7 @@ func (f FilePreview) text() string {
)
}
body, err := pixelapi.GetFile(f.FileInfo.ID)
body, err := f.PixelAPI.GetFile(f.FileInfo.ID)
if err != nil {
log.Error("Can't download text file for preview: %s", err)
return fmt.Sprintf(htmlOut, "",
@@ -189,6 +194,29 @@ func (f FilePreview) def() string {
f.FileInfo.FileName,
f.FileInfo.MimeType,
f.DownloadURL,
conf.ApiUrlExternal()+f.FileInfo.ThumbnailHREF,
f.APIURL+f.FileInfo.ThumbnailHREF,
)
}
// ServeFilePreviewDemo serves the content of the demo file. It contains a nice
// message to the human reviewers of the a-ads ad network so they can properly
// categorize the website.
func serveFilePreviewDemo(w http.ResponseWriter) {
io.WriteString(w,
`<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=desert"></script>
<div class="text-container"><pre class="pre-container linenums" style="width: 100%">
, __ _
/|/ \o | | | o
|___/ _ | | __| ,_ __, _ _
| | /\/ |/ |/ / | / | / | | / |/ |
| |_/ /\_/|__/|__/\_/|_/ |_/\_/|_/|_/ | |_/
This is a demonstration of Pixeldrain's file viewer.
The website automatically detects what kind of file you requested and prepares a page for viewing it properly. This is what a text file would look like on Pixeldrain. You can upload your own text file at pixeldrain.com/t.
Pixeldrain is a free service for sharing files with large or small groups of people. For more information visit the home page by pressing the home button on the toolbar at the left side of the screen.
Press the Details button or "i" for more info about Pixeldrain's file viewer.
</pre></div>`)
}

View File

@@ -5,16 +5,15 @@ import (
"net/http"
"strings"
"fornaxian.com/pixeldrain-web/log"
"fornaxian.com/pixeldrain-web/pixelapi"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/Fornaxian/log"
"github.com/julienschmidt/httprouter"
)
// ServeFileViewer controller for GET /u/:id
func ServeFileViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
func (wc *WebController) serveFileViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
if p.ByName("id") == "demo" {
ServeFileViewerDemo(w) // Required for a-ads.com quality check
wc.serveFileViewerDemo(w) // Required for a-ads.com quality check
return
}
@@ -29,7 +28,7 @@ func ServeFileViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params
var finfo []*pixelapi.FileInfo
for _, id := range ids {
inf := pixelapi.GetFileInfo(id)
inf := wc.api.GetFileInfo(id)
if inf == nil {
continue
}
@@ -37,7 +36,7 @@ func ServeFileViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params
}
if len(finfo) == 0 {
ServeNotFound(w, r)
wc.serveNotFound(w, r)
return
}
@@ -51,14 +50,14 @@ func ServeFileViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params
"date_lastview": "now",
"views": 0,
}
err = templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
err = wc.templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
"Title": fmt.Sprintf("%d files in Pixeldrain", len(finfo)),
"APIResponse": listdata,
"Type": "list",
"OGData": ogData.FromFile(*finfo[0]),
})
} else {
err = templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
err = wc.templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
"Title": fmt.Sprintf("%s ~ Pixeldrain file", finfo[0].FileName),
"APIResponse": finfo[0],
"Type": "file",
@@ -69,3 +68,24 @@ func ServeFileViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params
log.Error("Error executing template file_viewer: %s", err)
}
}
// ServeFileViewerDemo is a dummy API response that responds with info about a
// non-existent demo file. This is required by the a-ads ad network to allow for
// automatic checking of the presence of the ad unit on this page.
func (wc *WebController) serveFileViewerDemo(w http.ResponseWriter) {
wc.templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
"APIResponse": map[string]interface{}{
"id": "demo",
"file_name": "Demo file",
"date_upload": "2017-01-01 12:34:56",
"date_lastview": "2017-01-01 12:34:56",
"file_size": 123456789,
"views": 1,
"mime_type": "text/demo",
"description": "A file to demonstrate the viewer page",
"mime_image": "/res/img/mime/text.png",
"thumbnail": "/res/img/mime/text.png",
},
"Type": "file",
})
}

View File

@@ -1,52 +0,0 @@
package webcontroller
import (
"io"
"net/http"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
)
// ServeFileViewerDemo is a dummy API response that responds with info about a
// non-existent demo file. This is required by the a-ads ad network to allow for
// automatic checking of the presence of the ad unit on this page.
func ServeFileViewerDemo(w http.ResponseWriter) {
templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
"APIResponse": map[string]interface{}{
"id": "demo",
"file_name": "Demo file",
"date_upload": "2017-01-01 12:34:56",
"date_lastview": "2017-01-01 12:34:56",
"file_size": 123456789,
"views": 1,
"mime_type": "text/demo",
"description": "A file to demonstrate the viewer page",
"mime_image": "/res/img/mime/text.png",
"thumbnail": "/res/img/mime/text.png",
},
"Type": "file",
})
}
// ServeFilePreviewDemo serves the content of the demo file. It contains a nice
// message to the human reviewers of the a-ads ad network so they can properly
// categorize the website.
func ServeFilePreviewDemo(w http.ResponseWriter) {
io.WriteString(w,
`<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=desert"></script>
<div class="text-container"><pre class="pre-container linenums" style="width: 100%">
, __ _
/|/ \o | | | o
|___/ _ | | __| ,_ __, _ _
| | /\/ |/ |/ / | / | / | | / |/ |
| |_/ /\_/|__/|__/\_/|_/ |_/\_/|_/|_/ | |_/
This is a demonstration of Pixeldrain's file viewer.
The website automatically detects what kind of file you requested and prepares a page for viewing it properly. This is what a text file would look like on Pixeldrain. You can upload your own text file at pixeldrain.com/t.
Pixeldrain is a free service for sharing files with large or small groups of people. For more information visit the home page by pressing the home button on the toolbar at the left side of the screen.
Press the Details button or "i" for more info about Pixeldrain's file viewer.
</pre></div>`)
}

View File

@@ -1,17 +0,0 @@
package webcontroller
import (
"net/http"
"fornaxian.com/pixeldrain-web/log"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/julienschmidt/httprouter"
)
// ServeHistory is the controller for the upload history viewer
func ServeHistory(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
err := templates.Get().ExecuteTemplate(w, "history-cookies", nil)
if err != nil {
log.Error("Error executing template history: %s", err)
}
}

View File

@@ -1,14 +0,0 @@
package webcontroller
import (
"net/http"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/julienschmidt/httprouter"
)
// ServeHome serves the home page
func ServeHome(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
templates.Get().ExecuteTemplate(w, "home", nil)
}

View File

@@ -4,20 +4,18 @@ import (
"fmt"
"net/http"
"fornaxian.com/pixeldrain-web/log"
"fornaxian.com/pixeldrain-web/pixelapi"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/Fornaxian/log"
"github.com/julienschmidt/httprouter"
)
// ServeListViewer controller for GET /l/:id
func ServeListViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var list = pixelapi.GetList(p.ByName("id"))
func (wc *WebController) serveListViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var list = wc.api.GetList(p.ByName("id"))
if list.Error != nil {
if list.Error.ReqError {
log.Error("API request error occurred: %s", list.Error.Value)
}
ServeNotFound(w, r)
wc.serveNotFound(w, r)
return
}
@@ -30,7 +28,7 @@ func ServeListViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params
"title": list.Title,
"views": 0,
}
err = templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
err = wc.templates.Get().ExecuteTemplate(w, "file_viewer", map[string]interface{}{
"Title": fmt.Sprintf("%s ~ Pixeldrain list", list.Title),
"APIResponse": listdata,
"Type": "list",

View File

@@ -1,13 +0,0 @@
package webcontroller
import (
"net/http"
"fornaxian.com/pixeldrain-web/log"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
)
func ServeNotFound(w http.ResponseWriter, r *http.Request) {
log.Debug("Not Found: %s", r.URL)
templates.Get().ExecuteTemplate(w, "error", nil)
}

View File

@@ -1,14 +0,0 @@
package webcontroller
import (
"net/http"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/julienschmidt/httprouter"
)
// ServePaste serves the page that is used to upload plain text files
func ServePaste(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
templates.Get().ExecuteTemplate(w, "paste", nil)
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/julienschmidt/httprouter"
)
func GlobalCSSHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
func (wc *WebController) globalCSSHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Header().Add("Content-Type", "text/css; charset=utf-8")
var textColor = "hsl(0, 0%, 75%)"

View File

@@ -3,24 +3,24 @@ package templates
import (
"html/template"
"time"
"fornaxian.com/pixeldrain-web/conf"
)
var funcMap = template.FuncMap{
"bgPatternCount": bgPatternCount,
"debugMode": debugMode,
"apiUrl": apiURL,
func (tm *TemplateManager) funcMap() template.FuncMap {
return template.FuncMap{
"bgPatternCount": tm.bgPatternCount,
"debugMode": tm.debugMode,
"apiUrl": tm.apiURL,
}
}
func bgPatternCount() uint8 {
func (tm *TemplateManager) bgPatternCount() uint8 {
return uint8(time.Now().UnixNano() % 17)
}
func debugMode() bool {
return conf.DebugMode()
func (tm *TemplateManager) debugMode() bool {
return tm.debugModeEnabled
}
func apiURL() string {
return conf.ApiUrlExternal()
func (tm *TemplateManager) apiURL() string {
return tm.externalAPIEndpoint
}

View File

@@ -0,0 +1,61 @@
package templates
import (
"html/template"
"os"
"path/filepath"
"github.com/Fornaxian/log"
)
type TemplateManager struct {
templates *template.Template
// Config
templateDir string
externalAPIEndpoint string
debugModeEnabled bool
}
func New(templateDir, externalAPIEndpoint string, debugMode bool) *TemplateManager {
return &TemplateManager{
templateDir: templateDir,
externalAPIEndpoint: externalAPIEndpoint,
debugModeEnabled: debugMode,
}
}
// ParseTemplates parses the templates in the template directory which is
// defined in the config file
func (tm *TemplateManager) ParseTemplates() {
var templatePaths []string
filepath.Walk(tm.templateDir, func(path string, f os.FileInfo, err error) error {
if f.IsDir() {
return nil
}
templatePaths = append(templatePaths, path)
log.Info("Template found: %s", path)
return nil
})
tpl := template.New("")
// Import template functions from funcs.go
tpl = tpl.Funcs(tm.funcMap())
var err error
tpl, err = tpl.ParseFiles(templatePaths...)
if err != nil {
log.Error("Template parsing failed: %v", err)
}
// Swap out the old templates with the new templates, to minimize
// modifications to the original variable.
tm.templates = tpl
}
// Get returns the templates, so they can be used to render views
func (tm *TemplateManager) Get() *template.Template {
return tm.templates
}

View File

@@ -1,46 +0,0 @@
package templates
import (
"html/template"
"os"
"path/filepath"
"fornaxian.com/pixeldrain-web/conf"
"fornaxian.com/pixeldrain-web/log"
)
var templates *template.Template
var templatePaths []string
// ParseTemplates parses the templates in the template directory which is
// defined in the config file
func ParseTemplates() {
filepath.Walk(conf.TemplateDir(), func(path string, f os.FileInfo, err error) error {
if f.IsDir() {
return nil
}
templatePaths = append(templatePaths, path)
log.Info("Template found: %s", path)
return nil
})
tpl := template.New("")
// Import template functions from funcs.go
tpl = tpl.Funcs(funcMap)
var err error
tpl, err = tpl.ParseFiles(templatePaths...)
if err != nil {
log.Error("Template parsing failed: %v", err)
}
// Swap out the old templates with the new templates, to minimize
// modifications to the original variable.
templates = tpl
}
// Get returns the templates, so they can be used to render views
func Get() *template.Template {
return templates
}

View File

@@ -0,0 +1,81 @@
package webcontroller
import (
"net/http"
"fornaxian.com/pixeldrain-web/init/conf"
"fornaxian.com/pixeldrain-web/pixelapi"
"fornaxian.com/pixeldrain-web/webcontroller/templates"
"github.com/Fornaxian/log"
"github.com/julienschmidt/httprouter"
)
type WebController struct {
conf *conf.PixelWebConfig
api *pixelapi.PixelAPI
templates *templates.TemplateManager
staticResourceDir string
}
func New(r *httprouter.Router, prefix string, conf *conf.PixelWebConfig) *WebController {
var wc = &WebController{
conf: conf,
staticResourceDir: conf.StaticResourceDir,
}
wc.api = pixelapi.New(conf.APIURLInternal)
wc.templates = templates.New(
conf.TemplateDir,
conf.APIURLExternal,
conf.DebugMode,
)
wc.templates.ParseTemplates()
// Serve static files
r.ServeFiles(prefix+"/res/*filepath", http.Dir(wc.staticResourceDir+"/res"))
r.GET(prefix+"/" /* */, wc.serveTemplate("home"))
r.GET(prefix+"/favicon.ico" /* */, wc.serveFile("/favicon.ico"))
r.GET(prefix+"/global.css" /* */, wc.globalCSSHandler)
r.GET(prefix+"/api" /* */, wc.serveTemplate("apidoc"))
r.GET(prefix+"/history" /* */, wc.serveTemplate("history-cookies"))
r.GET(prefix+"/u/:id" /* */, wc.serveFileViewer)
r.GET(prefix+"/u/:id/preview" /**/, wc.serveFilePreview)
r.GET(prefix+"/l/:id" /* */, wc.serveListViewer)
r.GET(prefix+"/t" /* */, wc.serveTemplate("paste"))
r.NotFound = http.HandlerFunc(wc.serveNotFound)
return wc
}
func (wc *WebController) ReloadTemplates() {
wc.templates.ParseTemplates()
}
func (wc *WebController) serveTemplate(tpl string) httprouter.Handle {
return func(
w http.ResponseWriter,
r *http.Request,
p httprouter.Params,
) {
err := wc.templates.Get().ExecuteTemplate(w, tpl, nil)
if err != nil {
log.Error("Error executing template '%s': %s", tpl, err)
}
}
}
func (wc *WebController) serveFile(path string) httprouter.Handle {
return func(
w http.ResponseWriter,
r *http.Request,
p httprouter.Params,
) {
http.ServeFile(w, r, wc.staticResourceDir+"/favicon.ico")
}
}
func (wc *WebController) serveNotFound(w http.ResponseWriter, r *http.Request) {
log.Debug("Not Found: %s", r.URL)
wc.templates.Get().ExecuteTemplate(w, "error", nil)
}