forked from andrew-d/go-webapp-skeleton
/
main.go
145 lines (124 loc) · 3.92 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package main
import (
"bytes"
"net/http"
"time"
"github.com/Sirupsen/logrus"
"github.com/andrew-d/webhelpers"
webcontext "github.com/goji/context"
"github.com/jmoiron/sqlx"
"github.com/tylerb/graceful"
"github.com/zenazn/goji/web"
"golang.org/x/net/context"
"github.com/andrew-d/go-webapp-skeleton/conf"
"github.com/andrew-d/go-webapp-skeleton/datastore"
"github.com/andrew-d/go-webapp-skeleton/datastore/database"
"github.com/andrew-d/go-webapp-skeleton/log"
"github.com/andrew-d/go-webapp-skeleton/middleware"
"github.com/andrew-d/go-webapp-skeleton/router"
"github.com/andrew-d/go-webapp-skeleton/static"
)
// Generic structure that holds all created things - database connection,
// datastore, etc.
type Vars struct {
db *sqlx.DB
ds datastore.Datastore
log *logrus.Logger
}
func main() {
var vars Vars
// Create logger.
vars.log = log.NewLogger()
vars.log.WithFields(logrus.Fields{
"project_name": conf.ProjectName,
"version": conf.Version,
"revision": conf.Revision,
}).Info("initializing...")
// Connect to the database.
db, err := database.Connect(conf.C.DbType, conf.C.DbConn)
if err != nil {
vars.log.WithFields(logrus.Fields{
"err": err,
"db_type": conf.C.DbType,
"db_conn": conf.C.DbConn,
}).Error("Could not connect to database")
return
}
vars.db = db
// Create datastore.
vars.ds = database.NewDatastore(db)
// Create API router and add middleware.
apiMux := router.API()
apiMux.Use(middleware.Options)
apiMux.Use(middleware.JSON)
// Create web router and add middleware.
webMux := router.Web()
webMux.Use(webhelpers.Recoverer)
webMux.Use(ContextMiddleware(&vars))
webMux.Use(middleware.SetHeaders)
// "Mount" the API mux under the web mux, on the "/api" prefix.
webMux.Handle("/api/*", apiMux)
// Serve all static assets.
serveAssetAt := func(asset, path string) {
info, _ := static.AssetInfo(asset)
modTime := info.ModTime()
data := static.MustAsset(asset)
webMux.Get(path, func(w http.ResponseWriter, r *http.Request) {
vars.log.Debugf("serving asset: %s", asset)
http.ServeContent(w, r, asset, modTime, bytes.NewReader(data))
})
}
for _, asset := range static.AssetNames() {
vars.log.Debugf("adding route for asset: %s", asset)
serveAssetAt(asset, "/static/"+asset)
}
// Special case a bunch of assets that should be served from the root.
for _, asset := range []string{
"clientaccesspolicy.xml",
"crossdomain.xml",
"favicon.ico",
"humans.txt",
"robots.txt",
} {
// Note: only serve if we have this asset.
if _, err := static.Asset(asset); err == nil {
vars.log.Debugf("adding special route for asset: %s", asset)
serveAssetAt(asset, "/"+asset)
}
}
// Serve the index page if we have one.
for _, asset := range []string{"index.html", "index.htm"} {
// Note: only serve if we have this asset, and only serve the first
// option.
if _, err := static.Asset(asset); err == nil {
vars.log.Debugf("adding index route for asset: %s", asset)
serveAssetAt(asset, "/")
break
}
}
// We wrap the Request ID middleware and our logger 'outside' the mux, so
// all requests (including ones that aren't matched by the router) get
// logged.
var handler http.Handler = webMux
handler = webhelpers.LogrusLogger(vars.log, handler)
handler = webhelpers.RequestID(handler)
// Start serving
vars.log.Infof("starting server on: %s", conf.C.HostString())
graceful.Run(conf.C.HostString(), 10*time.Second, handler)
vars.log.Info("server finished")
}
// ContextMiddleware will add our variables to the per-request context.
func ContextMiddleware(vars *Vars) web.MiddlewareType {
mfn := func(c *web.C, h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
ctx = datastore.NewContext(ctx, vars.ds)
ctx = log.NewContext(ctx, vars.log)
// Add the context to the goji web context
webcontext.Set(c, ctx)
h.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
return mfn
}