This repository has been archived by the owner on Jun 4, 2022. It is now read-only.
/
main.go
201 lines (179 loc) · 6.48 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
// Smarthome: A completely self-built Smarthome-system written in Go
// https://github.com/MikMuellerDev/smarthome
package main
import (
"fmt"
"net/http"
"os"
"strconv"
"time"
"github.com/sirupsen/logrus"
"github.com/MikMuellerDev/smarthome/core/config"
"github.com/MikMuellerDev/smarthome/core/database"
"github.com/MikMuellerDev/smarthome/core/event"
"github.com/MikMuellerDev/smarthome/core/hardware"
"github.com/MikMuellerDev/smarthome/core/homescript"
"github.com/MikMuellerDev/smarthome/core/scheduler/automation"
"github.com/MikMuellerDev/smarthome/core/scheduler/scheduler"
"github.com/MikMuellerDev/smarthome/core/user"
"github.com/MikMuellerDev/smarthome/core/utils"
"github.com/MikMuellerDev/smarthome/server/api"
"github.com/MikMuellerDev/smarthome/server/middleware"
"github.com/MikMuellerDev/smarthome/server/routes"
"github.com/MikMuellerDev/smarthome/server/templates"
"github.com/MikMuellerDev/smarthome/services/camera"
"github.com/MikMuellerDev/smarthome/services/reminder"
)
var port = 8082 // Port used during development, can be overridden by config file or environment variables
func main() {
utils.Version = "0.0.26-beta-rc.3"
startTime := time.Now()
// Create logger
logLevel := logrus.TraceLevel
if newLogLevel, newLogLevelOk := os.LookupEnv("SMARTHOME_LOG_LEVEL"); newLogLevelOk {
switch newLogLevel {
case "TRACE":
logLevel = logrus.TraceLevel
case "DEBUG":
logLevel = logrus.DebugLevel
case "INFO":
logLevel = logrus.InfoLevel
case "WARN":
logLevel = logrus.WarnLevel
case "ERROR":
logLevel = logrus.ErrorLevel
case "FATAL":
logLevel = logrus.FatalLevel
default:
fmt.Printf("Invalid log level from environment variable: '%s'. Using TRACE\n", newLogLevel)
}
}
log, err := utils.NewLogger(logLevel)
if err != nil {
panic(err.Error())
}
// Initialize <module> loggers
config.InitLogger(log)
camera.InitLogger(log)
database.InitLogger(log)
middleware.InitLogger(log)
api.InitLogger(log)
routes.InitLogger(log)
templates.InitLogger(log)
user.InitLogger(log)
hardware.InitLogger(log)
event.InitLogger(log)
homescript.InitLogger(log)
automation.InitLogger(log)
scheduler.InitLogger(log)
reminder.InitLogger(log)
// Read config file
if err := config.ReadConfigFile(); err != nil {
log.Fatal("Failed to read config file: startup halted: ", err.Error())
}
configStruct := config.GetConfig()
if configStruct.Server.Port != 0 {
port = int(configStruct.Server.Port)
}
log.Debug("Loaded and successfully initialized config")
// Environment variables
/*
`SMARTHOME_ADMIN_PASSWORD`: If set, the admin user that is created on first launch will get this password instead of `admin`
`SMARTHOME_DB_DATABASE` : Sets the database name
`SMARTHOME_DB_HOSTNAME` : Sets the database hostname
`SMARTHOME_DB_PASSWORD` : Sets the database user's password
`SMARTHOME_DB_USER` : Sets the database user
*/
newAdminPassword := "admin"
if adminPassword, adminPasswordOk := os.LookupEnv("SMARTHOME_ADMIN_PASSWORD"); adminPasswordOk {
newAdminPassword = adminPassword
}
if dbUsername, dbUsernameOk := os.LookupEnv("SMARTHOME_DB_USER"); dbUsernameOk {
log.Debug("Selected SMARTHOME_DB_USER over value from config file")
configStruct.Database.Username = dbUsername
}
if dbPassword, dbPasswordOk := os.LookupEnv("SMARTHOME_DB_PASSWORD"); dbPasswordOk {
log.Debug("Selected SMARTHOME_DB_PASSWORD over value from config file")
configStruct.Database.Password = dbPassword
}
if dbDatabase, dbDatabaseOk := os.LookupEnv("SMARTHOME_DB_DATABASE"); dbDatabaseOk {
log.Debug("Selected SMARTHOME_DB_DATABASE over value from config file")
configStruct.Database.Database = dbDatabase
}
if dbHostname, dbHostnameOk := os.LookupEnv("SMARTHOME_DB_HOSTNAME"); dbHostnameOk {
log.Debug("Selected SMARTHOME_DB_HOSTNAME over value from config file")
configStruct.Database.Hostname = dbHostname
}
if webPort, webPortOk := os.LookupEnv("SMARTHOME_PORT"); webPortOk {
webPortInt, err := strconv.Atoi(webPort)
if err != nil {
log.Warn("Could not parse `SMARTHOME_PORT` to int, using 8082")
} else {
log.Debug("Selected `SMARTHOME_PORT` over default")
port = webPortInt
}
}
if dbPort, dbPortOk := os.LookupEnv("SMARTHOME_DB_PORT"); dbPortOk {
portInt, err := strconv.Atoi(dbPort)
if err != nil {
log.Warn("Could not parse `SMARTHOME_DB_PORT` to int, using value from config.json")
} else {
log.Debug("Selected SMARTHOME_DB_PORT over value from config file")
configStruct.Database.Port = portInt
}
}
// Initialize / connect to database, try 5 times before giving up
var dbErr error = nil
for i := 0; i <= 5; i++ {
dbErr = database.Init(configStruct.Database, newAdminPassword)
if dbErr == nil {
break
} else {
log.Warn("Failed to connect to database, retrying in 5 seconds")
time.Sleep(time.Second * 5)
}
}
if dbErr != nil {
log.Error("Failed to connect to database after 5 retries, exiting now")
panic(dbErr.Error())
}
// Run setup file if it exists
if err := config.RunSetup(); err != nil {
log.Fatal("Could not run setup: ", err.Error())
}
// If the server is in development mode, all logs should be flushed
if !configStruct.Server.Production {
if err := database.FlushAllLogs(); err != nil {
log.Fatal("Failed to flush logs: ", err.Error())
}
}
// Always flush old logs
// TODO: move deletion of old logs to a scheduler
log.Info("Flushing logs older than 30 days")
if err := database.FlushOldLogs(); err != nil {
log.Fatal("Failed to flush logs older that 30 days: ", err.Error())
}
// Initializes the automation scheduler
if err := automation.Init(); err != nil {
log.Fatal("Failed to activate automation system: ", err.Error())
}
// Initializes the normal scheduler
if err := scheduler.Init(); err != nil {
log.Fatal("Failed to activate scheduler system: ", err.Error())
}
// Initialize notification scheduler for reminders
if err := reminder.InitSchedule(); err != nil {
log.Fatal("Failed to activate reminder scheduler: ", err.Error())
}
// Init the hardware handler
hardware.Init() // Needed for initializing atomics
r := routes.NewRouter()
middleware.Init(configStruct.Server.Production)
templates.LoadTemplates("./web/dist/html/*.html")
http.Handle("/", r)
event.Info("System Started", fmt.Sprintf("The Smarthome server completed startup in %.2f seconds", time.Since(startTime).Seconds()))
log.Info(fmt.Sprintf("Smarthome v%s is running on http://localhost:%d", utils.Version, port))
if err = http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
panic(err)
}
}