-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.go
111 lines (96 loc) · 2.96 KB
/
server.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
package apiary
import (
"context"
"log"
"math"
"net/http"
"time"
"github.com/chnm/apiary/db"
"github.com/gorilla/mux"
_ "github.com/jackc/pgx/v4" // Driver for database
"github.com/jackc/pgx/v4/pgxpool"
cache "github.com/victorspringer/http-cache"
"github.com/victorspringer/http-cache/adapter/memory"
)
// The Config type stores configuration which is read from environment variables.
type Config struct {
dbconn string
logging bool // Whether or not to write access logs; errors/status are always logged
address string // The address at which this will be hosted, e.g.: localhost:8090
}
// The Server type shares access to the database.
type Server struct {
Server *http.Server
DB *pgxpool.Pool
Router *mux.Router
Config Config
Cache *cache.Client
}
// NewServer creates a new Server and connects to the database or fails trying.
func NewServer(ctx context.Context) *Server {
s := Server{}
// Read the configuration from environment variables. The `getEnv()` function
// will provide a default.
s.Config.dbconn = getEnv("APIARY_DB", "")
s.Config.logging = getEnv("APIARY_LOGGING", "on") == "on"
s.Config.address = getEnv("APIARY_INTERFACE", "0.0.0.0") + ":" + getEnv("APIARY_PORT", "8090")
// Connect to the database then store the database in the struct.
log.Println("connecting to the database")
dbTimeout, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
pool, err := db.Connect(dbTimeout, s.Config.dbconn)
if err != nil {
log.Fatalln("error connecting to the database:", err)
}
s.DB = pool
// Set up the in-memory cache
memcached, err := memory.NewAdapter(
memory.AdapterWithAlgorithm(memory.LRU),
memory.AdapterWithCapacity(int(math.Pow(1000, 2))), // 1000^3 = gigabyte
)
if err != nil {
log.Fatal("error setting up memory cache:", err)
}
cacheClient, err := cache.NewClient(
cache.ClientWithAdapter(memcached),
cache.ClientWithTTL(1*time.Hour),
cache.ClientWithRefreshKey("nocache"),
)
if err != nil {
log.Fatal("error setting up memory cache:", err)
}
s.Cache = cacheClient
// Create the router, store it in the struct, initialize the routes, and
// register the middleware.
router := mux.NewRouter()
s.Router = router
s.Routes()
s.Middleware()
s.Server = &http.Server{
Addr: s.Config.address,
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
IdleTimeout: time.Second * 60,
Handler: s.Router,
}
return &s
}
// Run starts the API server.
func (s *Server) Run() error {
log.Printf("starting the server on http://%s\n", s.Config.address)
err := s.Server.ListenAndServe()
if err == http.ErrServerClosed {
return nil
}
return err
}
// Shutdown closes the connection to the database and shutsdown the server.
func (s *Server) Shutdown() {
log.Println("closing the connection to the database")
s.DB.Close()
log.Println("shutting down the web server")
err := s.Server.Shutdown(context.TODO())
if err != nil {
log.Println("error shutting down web server:", err)
}
}