-
Notifications
You must be signed in to change notification settings - Fork 2
/
config.go
183 lines (139 loc) · 4.21 KB
/
config.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package pto3
import (
"encoding/json"
"io/ioutil"
"log"
"net/url"
"os"
"strings"
"github.com/go-pg/pg"
)
// PTOConfiguration contains a configuration of a PTO server
type PTOConfiguration struct {
// Address/port to bind to
BindTo string
// base URL of web service
BaseURL string
// ...this right here is effing annoying but i'm not writing a custom unmarshaler just for that...
baseURL *url.URL
// Access-Control-Allow-Origin header on responses
AllowOrigin string
// API key file path
APIKeyFile string
// Certificate file path
CertificateFile string
// Private key file path
PrivateKeyFile string
// File to serve for / (empty == serve paths to enabled apps)
RootFile string
// Directory to serve files from for /static
StaticRoot string
// base path for raw data store; empty for no RDS.
RawRoot string
// Filetype registry for RDS.
ContentTypes map[string]string
// base path for query cache data store; empty for no query cache.
QueryCacheRoot string
// PostgreSQL options for connection to observation database; leave default for no OBS.
ObsDatabase pg.Options
// Page size for things that can be paginated
PageLength int
// Immediate query delay
ImmediateQueryDelay int
// Number of concurrent queries
ConcurrentQueries int
// Access logging file path
AccessLogPath string
accessLogger *log.Logger
// Path to configuration file
ConfigFilePath string
}
// LinkTo creates a link to a relative URL from the configuration's base URL
func (config *PTOConfiguration) LinkTo(relative string) (string, error) {
// Make sure relative doesn't start with a '/'. See #119.
relative = strings.TrimPrefix(relative, "/")
u, err := url.Parse(relative)
if err != nil {
return "", PTOWrapError(err)
}
return config.baseURL.ResolveReference(u).String(), nil
}
// AccessLogger returns a logger for the web API to log accesses to
func (config *PTOConfiguration) AccessLogger() *log.Logger {
return config.accessLogger
}
func NewConfigFromJSON(b []byte) (*PTOConfiguration, error) {
var config PTOConfiguration
var err error
if err := json.Unmarshal(b, &config); err != nil {
return nil, err
}
// Make sure baseURL ends with a '/'. See #119.
if !strings.HasSuffix(config.BaseURL, "/") {
config.BaseURL = config.BaseURL + "/"
}
config.baseURL, err = url.Parse(config.BaseURL)
if err != nil {
return nil, err
}
if config.AccessLogPath == "" {
config.accessLogger = log.New(os.Stderr, "", log.LstdFlags)
} else {
accessLogFile, err := os.Open(config.AccessLogPath)
if err != nil {
return nil, err
}
config.accessLogger = log.New(accessLogFile, "access: ", log.LstdFlags)
}
// default page length is 1000
if config.PageLength == 0 {
config.PageLength = 1000
}
// default immediate query delay is 2s
if config.ImmediateQueryDelay == 0 {
config.ImmediateQueryDelay = 2000
}
// default query concurrency is 8
if config.ConcurrentQueries == 0 {
config.ConcurrentQueries = 8
}
// default pool size is 20; if this is 0, pgo-pg will set the pool size
// to 10 times the number of processors. on the main machine which runs
// ptosrv, we have 56 processors, which means that calling pg.Connect
// twice will exhaust the maximum number of file descriptors per process,
// which is 1024.
config.ObsDatabase.PoolSize = 20
return &config, nil
}
func NewConfigFromFile(filename string) (*PTOConfiguration, error) {
b, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
out, err := NewConfigFromJSON(b)
if err != nil {
return nil, err
}
out.ConfigFilePath = filename
return out, nil
}
var DefaultConfigPaths = []string{"ptoconfig.json", "~/.ptoconfig.json", "/etc/pto/ptoconfig.json"}
func NewConfigWithDefault(filename string) (*PTOConfiguration, error) {
var configPaths []string
if filename != "" {
configPaths = make([]string, len(DefaultConfigPaths)+1)
copy(configPaths[1:], DefaultConfigPaths)
configPaths[0] = filename
} else {
configPaths = DefaultConfigPaths
}
for _, configpath := range configPaths {
_, err := os.Stat(configpath)
if err == nil {
return NewConfigFromFile(configpath)
} else if !os.IsNotExist(err) {
return nil, PTOWrapError(err)
}
}
return nil, PTOErrorf("no configuration file found in %v", configPaths)
}