-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
133 lines (119 loc) · 3.52 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
package main
import (
"log"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gorilla/context"
"github.com/justinas/alice"
"gopkg.in/mgo.v2"
)
func main() {
log.SetPrefix("[main] ")
if os.Getenv(EnvDialURL) == "" {
log.Fatalln("Environment not configured. Exiting...")
}
log.Printf("Connecting to %v", os.Getenv(EnvDialURL))
session, err := mgo.Dial(os.Getenv(EnvDialURL))
if err != nil {
log.Fatalf("Failed to create a session: %v\n", err.Error())
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
err = session.Ping()
if err != nil {
log.Fatalf("Failed to ping DB: %v\n", err.Error())
}
//
// Start the server
//
exitCh := make(chan bool, 1)
go func() {
//
// Handler(s)
//
bucketHandler := NewBucketWebHandler()
bucketHandler.Session = session
objectHandler := NewObjectWebHandler()
objectHandler.Session = session
//
// Middleware chain (mind the order!)
//
defaultChain := alice.New(
context.ClearHandler, // cleanup ctx to avoid memory leakage
LoggingHandler, // basic requests logging
RecoverHandler, // transform panics into 500 responses
InfoHeadersHandler, // dummy handler to inject some info headers
)
jsonTypeHandler := NewContentTypeHandler("application/json")
jsonChain := alice.New(
context.ClearHandler, // cleanup ctx to avoid memory leakage
LoggingHandler, // basic requests logging
RecoverHandler, // transform panics into 500 responses
jsonTypeHandler, // check content-type for modification requests
InfoHeadersHandler, // dummy handler to inject some info headers
JSONRenderingHandler, // always set JSON content-type for this API
)
//
// Routing setup
//
router := newRouter()
// Bucket API
router.head("/buckets/:name", jsonChain.ThenFunc(bucketHandler.CheckExists))
router.get("/buckets/:name", jsonChain.ThenFunc(bucketHandler.Retreive))
router.delete("/buckets/:name", jsonChain.ThenFunc(bucketHandler.Delete))
// Object API
router.post("/objects", defaultChain.ThenFunc(objectHandler.Create))
router.put("/objects/:id", jsonChain.ThenFunc(objectHandler.Update))
router.head("/objects/:id", jsonChain.ThenFunc(objectHandler.CheckExists))
router.get("/objects/:id", defaultChain.ThenFunc(objectHandler.Download))
router.get("/objects/:id/meta", jsonChain.ThenFunc(objectHandler.About))
router.delete("/objects/:id", jsonChain.ThenFunc(objectHandler.Delete))
// Server setup
addr := os.Getenv(EnvBindAddr)
if addr == "" {
addr = ":5000"
}
s := &http.Server{
Addr: addr,
Handler: router,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
MaxHeaderBytes: 1 << 20,
}
// Create binding address listener
listener, listenErr := net.Listen("tcp", addr)
if listenErr != nil {
log.Println("Could not listen: %s", listenErr)
exitCh <- true
return
}
defer listener.Close()
log.Println("RESTful API Server listening", addr)
serveErr := s.Serve(listener)
if serveErr != nil {
log.Println("Error in Serve:", serveErr)
exitCh <- true
}
}()
// Setup signal catcher for the server's proper shutdown
c := make(chan os.Signal, 1)
signal.Notify(c,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
select {
case s := <-c:
log.Println("Caught signal", s.String())
case <-exitCh:
log.Println("Caught exit from one of the servers")
}
log.Println("Stopping the server...")
// Tidy up and tear down
log.Println("Tearing down...")
log.Fatalln("Finished - bye bye. ;-)")
}