Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
029a11fd96 | ||
|
|
e9edaf13ee | ||
|
|
3c2003767e | ||
|
|
09f4fef613 | ||
|
|
85296b4e1b | ||
|
|
04fa2f73a7 | ||
|
|
7c191f8a69 | ||
|
|
a6494ae0a1 | ||
|
|
a926bdc955 | ||
|
|
d76a9bff9f | ||
|
|
4a981bf69c | ||
|
|
5914f93881 | ||
|
|
8096c76b1e | ||
|
|
d98ef7a4a9 | ||
|
|
e5e9e5f494 | ||
|
|
31cd542929 |
+34
-9
@@ -1,15 +1,40 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"mcquay.me/web"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
http.Handle(
|
port := 8000
|
||||||
"/",
|
if os.Getenv("PORT") != "" {
|
||||||
http.FileServer(
|
p, err := strconv.Atoi(os.Getenv("PORT"))
|
||||||
http.Dir("."),
|
if err != nil {
|
||||||
),
|
fmt.Fprintf(os.Stderr, "couldn't parse port: %v\n", err)
|
||||||
)
|
os.Exit(1)
|
||||||
if err := http.ListenAndServe(":8000", nil); err != nil {
|
}
|
||||||
panic(err)
|
port = p
|
||||||
|
}
|
||||||
|
|
||||||
|
static := ""
|
||||||
|
if s := os.Getenv("STATIC"); s != "" {
|
||||||
|
static = s
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := ""
|
||||||
|
if t := os.Getenv("TEMPLATES"); t != "" {
|
||||||
|
tmpl = t
|
||||||
|
}
|
||||||
|
|
||||||
|
sm := http.NewServeMux()
|
||||||
|
|
||||||
|
web.NewSite(sm, static, tmpl)
|
||||||
|
if err := http.ListenAndServe(fmt.Sprintf(":%d", port), sm); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "problem serving: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2015, smcquay
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of web nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
@@ -50,3 +50,7 @@ a {
|
|||||||
padding-top: 30px;
|
padding-top: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tiny {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
|
||||||
<title>smcquay</title>
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/sm.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="content">
|
|
||||||
<div id="title">
|
|
||||||
<a href="https://sec.mcquay.me">smcquay</a>
|
|
||||||
</div>
|
|
||||||
<div id="pic">
|
|
||||||
<a href="https://sec.mcquay.me"><img src="/img/smcquay.png"></a>
|
|
||||||
</div>
|
|
||||||
<div id="info">
|
|
||||||
<p>
|
|
||||||
My name is <a href="http://stephen.mcquay.me">Stephen McQuay</a>,
|
|
||||||
<a href="https://twitter.com/smcquay">smcquay</a> on the internet.
|
|
||||||
I speak <a href="https://golang.org">gopher</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-2869147-4', 'auto'); ga('send', 'pageview'); </script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{{ define "base" }}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||||
|
<title>ωτφ</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/css/sm.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ template "body" . }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{ end }}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{{ define "body" }}
|
||||||
|
<div id="content">
|
||||||
|
<div id="title">
|
||||||
|
<a href="https://s.mcquay.me">smcquay</a>
|
||||||
|
</div>
|
||||||
|
<div id="pic">
|
||||||
|
<a href="https://s.mcquay.me"><img src="/static/img/smcquay.png"></a>
|
||||||
|
</div>
|
||||||
|
<div id="info">
|
||||||
|
<p>
|
||||||
|
My name is <a href="http://stephen.mcquay.me">Stephen McQuay</a>.
|
||||||
|
</p>
|
||||||
|
<p class="tiny">
|
||||||
|
Your visit occured {{ .time }}.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TemplateGetter defines what needs to be implemented to be able to fetch
|
||||||
|
// templates for use by a Site.
|
||||||
|
type TemplateGetter interface {
|
||||||
|
Get(name string) (*template.Template, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disk keeps track of the location of the root directory of the template
|
||||||
|
// directory.
|
||||||
|
type Disk struct {
|
||||||
|
Root string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get attempts to merge the requested name+.html with base.html found at root.
|
||||||
|
func (d Disk) Get(name string) (*template.Template, error) {
|
||||||
|
p := filepath.Join(d.Root, name+".html")
|
||||||
|
return template.New("").ParseFiles(p, filepath.Join(d.Root, "base.html"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetTemplate pulls templates from an assetfs.
|
||||||
|
type AssetTemplate struct {
|
||||||
|
sync.RWMutex
|
||||||
|
Asset func(name string) ([]byte, error)
|
||||||
|
|
||||||
|
cache map[string]*template.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAssetTemplate returns a ready-to-use AssetTemplate.
|
||||||
|
func NewAssetTemplate(asset func(string) ([]byte, error)) *AssetTemplate {
|
||||||
|
return &AssetTemplate{
|
||||||
|
Asset: asset,
|
||||||
|
cache: map[string]*template.Template{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get attempts to merge the requested name+.html with base.html found at root.
|
||||||
|
func (at *AssetTemplate) Get(name string) (*template.Template, error) {
|
||||||
|
at.RLock()
|
||||||
|
if t, ok := at.cache[name]; ok {
|
||||||
|
at.RUnlock()
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
at.RUnlock()
|
||||||
|
|
||||||
|
base, err := at.Asset("templates/base.html")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not get base contents: %v", err)
|
||||||
|
}
|
||||||
|
page, err := at.Asset(fmt.Sprintf("templates/%s.html", name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not get base contents: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := template.New(name).Parse(string(base))
|
||||||
|
if err != nil {
|
||||||
|
return t, fmt.Errorf("parsing base: %v", err)
|
||||||
|
}
|
||||||
|
t, err = t.Parse(string(page))
|
||||||
|
if err != nil {
|
||||||
|
return t, fmt.Errorf("parsing specific page %s: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
at.Lock()
|
||||||
|
at.cache[name] = t
|
||||||
|
at.Unlock()
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
assetfs "github.com/elazarl/go-bindata-assetfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go get github.com/jteeuwen/go-bindata/...
|
||||||
|
//go:generate go get github.com/elazarl/go-bindata-assetfs/...
|
||||||
|
//go:generate rm -f static.go
|
||||||
|
//go:generate go-bindata -o static.go -pkg=web static/... templates/...
|
||||||
|
|
||||||
|
type Site struct {
|
||||||
|
tmpl TemplateGetter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSite(sm *http.ServeMux, static, templates string) *Site {
|
||||||
|
s := &Site{}
|
||||||
|
|
||||||
|
var fs http.FileSystem
|
||||||
|
if p, d := filepath.Split(static); d == "static" {
|
||||||
|
static = p
|
||||||
|
}
|
||||||
|
fs = http.Dir(static)
|
||||||
|
if static == "" {
|
||||||
|
fs = &assetfs.AssetFS{
|
||||||
|
Asset: Asset,
|
||||||
|
AssetDir: AssetDir,
|
||||||
|
AssetInfo: AssetInfo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tmpl = NewAssetTemplate(Asset)
|
||||||
|
if templates != "" {
|
||||||
|
s.tmpl = Disk{templates}
|
||||||
|
}
|
||||||
|
|
||||||
|
sm.HandleFunc("/", s.Home)
|
||||||
|
sm.Handle(
|
||||||
|
"/static/",
|
||||||
|
http.FileServer(fs),
|
||||||
|
)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Site) Home(w http.ResponseWriter, req *http.Request) {
|
||||||
|
c := map[string]string{
|
||||||
|
"time": time.Now().Format(time.Stamp),
|
||||||
|
}
|
||||||
|
tmpl, err := s.tmpl.Get("home")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("not found: %v", err), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tmpl.ExecuteTemplate(w, "base", c)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user