-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
355 lines (295 loc) · 10.3 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
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// Main
package main
import (
"fmt"
"os"
"path"
"path/filepath"
"runtime"
"strconv"
child_process_manager "github.com/AgustinSRG/go-child-process-manager"
)
const BACKEND_VERSION = "1.20.2"
type BackendOptions struct {
debug bool // Debug mode
logRequests bool
// Run modes
daemon bool
initialize bool
clean bool
fix bool
recover bool
// Port + Bind
port string
bindAddr string
// Lock
skipLock bool
// FFmpeg
ffmpegPath string
ffprobePath string
// Vault
vaultPath string
// Temp path
tempPath string
unencryptedTempPath string
// Preview cache size
previewsCacheSize int
}
const DEFAULT_PREVIEWS_CACHE_SIZE = 1024
var (
GLOBAL_VAULT *Vault = nil
)
func GetVault() *Vault {
return GLOBAL_VAULT
}
// Program entry point
func main() {
// Read arguments
args := os.Args
options := BackendOptions{
ffmpegPath: os.Getenv("FFMPEG_PATH"),
ffprobePath: os.Getenv("FFPROBE_PATH"),
vaultPath: "./vault",
tempPath: "./vault/temp",
unencryptedTempPath: os.Getenv("TEMP_PATH"),
port: "",
bindAddr: "",
previewsCacheSize: DEFAULT_PREVIEWS_CACHE_SIZE,
}
if options.ffmpegPath == "" {
if runtime.GOOS == "windows" {
options.ffmpegPath = "/ffmpeg/bin/ffmpeg.exe"
} else {
options.ffmpegPath = "/usr/bin/ffmpeg"
}
}
if options.ffprobePath == "" {
if runtime.GOOS == "windows" {
options.ffprobePath = "/ffmpeg/bin/ffprobe.exe"
} else {
options.ffprobePath = "/usr/bin/ffprobe"
}
}
if options.unencryptedTempPath == "" {
userCacheDir, err := os.UserCacheDir()
if err != nil {
LogError(err)
os.Exit(1)
}
options.unencryptedTempPath = path.Join(userCacheDir, "PersonalMediaVault", "temp")
}
for i := 1; i < len(args); i++ {
arg := args[i]
if arg == "--debug" {
options.debug = true
} else if arg == "--log-requests" {
options.logRequests = true
} else if arg == "--help" || arg == "-h" {
printHelp()
return
} else if arg == "--version" || arg == "-v" {
printVersion()
return
} else if arg == "--daemon" || arg == "-d" {
options.daemon = true
} else if arg == "--clean" || arg == "-c" {
options.clean = true
} else if arg == "--cors-insecure" {
CORS_INSECURE_MODE_ENABLED = true
} else if arg == "--init" || arg == "-i" {
options.initialize = true
} else if arg == "--skip-lock" || arg == "-sl" {
options.skipLock = true
} else if arg == "--port" || arg == "-p" {
if i == len(args)-1 {
fmt.Println("The option '--port' requires a value")
os.Exit(1)
}
options.port = args[i+1]
i++
} else if arg == "--launch-tag" {
if i == len(args)-1 {
fmt.Println("The option '--launch-tag' requires a value")
os.Exit(1)
}
LAUNCHER_TAG = args[i+1]
i++
} else if arg == "--bind" || arg == "-b" {
if i == len(args)-1 {
fmt.Println("The option '--bind' requires a value")
os.Exit(1)
}
options.bindAddr = args[i+1]
i++
} else if arg == "--vault-path" || arg == "-vp" {
if i == len(args)-1 {
fmt.Println("The option '--vault-path' requires a value")
os.Exit(1)
}
options.vaultPath = args[i+1]
options.tempPath = path.Join(options.vaultPath, "temp")
i++
} else if arg == "--fix-consistency" {
options.fix = true
} else if arg == "--recover" {
options.recover = true
} else if arg == "--cache-size" {
if i == len(args)-1 {
fmt.Println("The option '--cache-size' requires a value")
os.Exit(1)
}
cacheSize, err := strconv.Atoi(args[i+1])
if err != nil {
fmt.Println("The option '--cache-size' requires a valid integer as an argument")
os.Exit(1)
}
options.previewsCacheSize = cacheSize
i++
} else {
fmt.Println("Invalid argument: " + arg)
os.Exit(1)
}
}
if options.daemon || options.clean || options.initialize || options.fix {
if !options.skipLock {
// Setup lockfile
if !TryLockVault(options.vaultPath) {
fmt.Println("Error: The vault is already in use. If this is not true, please remove the file vault.lock in your vault folder.")
os.Exit(4)
}
}
}
SetTempFilesPath(options.tempPath) // Set temporal files path
if options.initialize {
InitializeCredentialsPath(options.vaultPath)
}
if options.clean {
LogInfo("Cleaning vault temporal files...")
ClearTemporalFilesPath()
}
if options.daemon {
err := child_process_manager.InitializeChildProcessManager()
if err != nil {
fmt.Println("Error: " + err.Error())
os.Exit(1)
}
defer child_process_manager.DisposeChildProcessManager() //nolint:errcheck
if _, err := os.Stat(options.ffmpegPath); err != nil {
fmt.Println("Error: Could not find 'ffmpeg' at specified location: " + options.ffmpegPath)
os.Exit(1)
}
if _, err := os.Stat(options.ffprobePath); err != nil {
fmt.Println("Error: Could not find 'ffprobe' at specified location: " + options.ffprobePath)
os.Exit(1)
}
SetFFMPEGBinaries(options.ffmpegPath, options.ffprobePath) // Set FFMPEG paths
SetDebugLogEnabled(options.debug) // Log debug mode
SetRequestLogEnabled(options.logRequests) // Log requests
// Create and initialize vault
vault := Vault{}
err = vault.Initialize(options.vaultPath, options.previewsCacheSize)
if err != nil {
fmt.Println("Error: " + err.Error())
os.Exit(1)
}
absolutePath, err := filepath.Abs(options.vaultPath)
if err != nil {
fmt.Println("Error: " + err.Error())
os.Exit(1)
}
LogInfo("Openned vault: " + absolutePath)
GLOBAL_VAULT = &vault
options.unencryptedTempPath = path.Join(options.unencryptedTempPath, vault.credentials.GetFingerprint())
SetUnencryptedTempFilesPath(options.unencryptedTempPath)
if options.clean {
LogInfo("Cleaning unencrypted temporal files...")
ClearUnencryptedTempFilesPath()
}
if options.recover {
LogInfo("Recovering assets...")
RecoverVaultAssets(&vault)
}
if options.fix {
LogInfo("Fixing vault consistency...")
FixVaultConsistency(&vault)
}
// Create and run HTTP server
RunHTTPServer(options.port, options.bindAddr, false)
} else if options.clean || options.fix || options.recover {
vault := Vault{}
err := vault.Initialize(options.vaultPath, options.previewsCacheSize)
if err != nil {
fmt.Println("Error: " + err.Error())
os.Exit(1)
}
options.unencryptedTempPath = path.Join(options.unencryptedTempPath, vault.credentials.GetFingerprint())
SetUnencryptedTempFilesPath(options.unencryptedTempPath)
if options.clean {
LogInfo("Cleaning unencrypted temporal files...")
ClearUnencryptedTempFilesPath()
}
if options.recover {
LogInfo("Recovering assets...")
RecoverVaultAssets(&vault)
}
if options.fix {
LogInfo("Fixing vault consistency...")
FixVaultConsistency(&vault)
}
return
} else if options.initialize {
return
} else {
printHelp()
}
}
// Prints help to standard output
func printHelp() {
fmt.Println("Usage: pmvd [OPTIONS]")
fmt.Println(" OPTIONS:")
fmt.Println(" --help, -h Prints command line options.")
fmt.Println(" --version, -v Prints version.")
fmt.Println(" --daemon, -d Runs backend daemon.")
fmt.Println(" --init, -i Initializes the vault. Asks for username and password.")
fmt.Println(" --clean, -c Cleans temporal path before starting the daemon.")
fmt.Println(" --port -p <port> Sets the listening port. By default 80 (or 443 if using SSL).")
fmt.Println(" --bind -b <bind-addr> Sets the bind address. By default it binds all interfaces.")
fmt.Println(" --vault-path, -vp <path> Sets the data storage path for the vault.")
fmt.Println(" --cache-size <size> Sets the LRU cache size. By default is can hold 1024 elements.")
fmt.Println(" DEBUG OPTIONS:")
fmt.Println(" --skip-lock Ignores vault lockfile.")
fmt.Println(" --fix-consistency Fixes vault consistency at startup (takes some time).")
fmt.Println(" --recover Recovers non-indexed media assets.")
fmt.Println(" --debug Enables debug mode.")
fmt.Println(" --log-requests Enables logging requests to standard output.")
fmt.Println(" --cors-insecure Allows all CORS requests (insecure, for development).")
fmt.Println(" --launch-tag <tag> Sets launcher tag (for launcher use).")
fmt.Println(" ENVIRONMENT VARIABLES:")
fmt.Println(" FFMPEG_PATH Path to ffmpeg binary.")
fmt.Println(" FFPROBE_PATH Path to ffprobe binary.")
fmt.Println(" TEMP_PATH Temporal path to store things like uploaded files or to use for FFMPEG encoding.")
fmt.Println(" Note: It should be in a different filesystem if the vault is stored in an unsafe environment.")
fmt.Println(" By default, this will be stored in ~/.pmv/temp")
fmt.Println(" FRONTEND_PATH Path to static frontend.")
fmt.Println(" SSL_CERT HTTPS certificate (.pem) path.")
fmt.Println(" SSL_KEY HTTPS private key (.pem) path.")
fmt.Println(" USING_PROXY Set to 'YES' if you are using a reverse proxy.")
fmt.Println(" TEMP_FILE_DELETE_MODE Set it to 'SECURE' to clear all the bytes of temporal files (secure delete).")
fmt.Println(" VAULT_INITIAL_USER The initial vault username to set if the vault folder is empty.")
fmt.Println(" VAULT_INITIAL_PASSWORD The initial vault password to set if the vault folder is empty.")
}
// Prints version to standard output
func printVersion() {
fmt.Println("---------------------------------------------------")
fmt.Println("- _____ __ __ __ __")
fmt.Println("- | __ \\ | \\/ | \\ \\ / /")
fmt.Println("- | |__) | | \\ / | \\ \\ / /")
fmt.Println("- | ___/ | |\\/| | \\ \\/ /")
fmt.Println("- | | | | | | \\ /")
fmt.Println("- |_| |_| |_| \\/")
fmt.Println("---------------------------------------------------")
fmt.Println("- Personal Media Vault (Backend)")
fmt.Println("- Version " + BACKEND_VERSION)
fmt.Println("- https://github.com/AgustinSRG/PersonalMediaVault")
fmt.Println("---------------------------------------------------")
}