-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathmain.go
216 lines (176 loc) · 5.55 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
//go:generate goversioninfo -icon=icon.ico -manifest=slashdiablo-launcher.exe.manifest -64
package main
import (
"bufio"
"errors"
"os"
"strconv"
"github.com/nokka/goqmlframeless"
"github.com/nokka/slashdiablo-launcher/bridge"
ladderClient "github.com/nokka/slashdiablo-launcher/clients/ladder"
"github.com/nokka/slashdiablo-launcher/clients/slashdiablo"
"github.com/nokka/slashdiablo-launcher/config"
"github.com/nokka/slashdiablo-launcher/d2"
"github.com/nokka/slashdiablo-launcher/ladder"
"github.com/nokka/slashdiablo-launcher/log"
"github.com/nokka/slashdiablo-launcher/news"
"github.com/nokka/slashdiablo-launcher/storage"
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/quick"
"github.com/therecipe/qt/widgets"
)
func main() {
// Environment variables set when building.
var (
debugMode = envBool("DEBUG_MODE", false)
environment = envString("ENVIRONMENT", "production")
buildVersion = envString("BUILD_VERSION", "v1.1.2")
)
// Set app context.
core.QCoreApplication_SetApplicationName("Slashdiablo launcher")
core.QCoreApplication_SetOrganizationName("slashdiablo.net")
core.QCoreApplication_SetOrganizationDomain("slashdiablo.net")
core.QCoreApplication_SetApplicationVersion("1.1.2")
// Enable high dpi scaling, useful for devices with high pixel density displays.
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
// Create base application.
app := widgets.NewQApplication(len(os.Args), os.Args)
// Create new frameless window.
fw := goqmlframeless.NewWindow(goqmlframeless.Options{
Width: 1024,
Height: 600,
Alpha: 1.0,
Color: goqmlframeless.RGB{R: 3, G: 2, B: 2},
})
// QML Widget that will be used to draw on.
qmlWidget := quick.NewQQuickWidget(nil)
qmlWidget.SetResizeMode(quick.QQuickWidget__SizeRootObjectToView)
// Add QML widget to layout.
fw.Layout.AddWidget(qmlWidget, 0, 0)
configPath, err := getConfigPath()
if err != nil {
os.Exit(0)
}
// Data directory is a requirement for the app.
os.MkdirAll(configPath, storage.Permissions)
// Setup file logger.
logger := log.NewLogger(configPath)
// Enable debugger if it was enabled through the env variable.
if debugMode {
enableDebugger(logger)
}
// Setup local storage.
store := storage.NewStore(configPath)
if err := store.Load(); err != nil {
logger.Error(errors.New("unable to load config"))
os.Exit(0)
}
conf, err := store.Read()
if err != nil {
logger.Error(errors.New("unable to read config"))
os.Exit(0)
}
// Models.
lm := ladder.NewTopLadderModel(nil)
gm := config.NewGameModel(nil)
nm := news.NewModel(nil)
fm := d2.NewFileModel(nil)
// Setup clients.
sc := slashdiablo.NewClient()
lc := ladderClient.NewClient()
// Setup services.
cs := config.NewService(sc, store, gm)
d2s := d2.NewService(sc, cs, logger, fm)
ls := ladder.NewService(lc, lm)
ns := news.NewService(sc, nm)
// Populate the game model with the game config
// before passing it to the config bridge.
populateGameModel(conf, gm)
// Setup QML bridges with all dependencies.
diabloBridge := bridge.NewDiablo(d2s, fm, conf.LaunchDelay, logger)
configBridge := bridge.NewConfig(cs, gm, configPath, logger)
ladderBridge := bridge.NewLadder(ls, lm, logger)
newsBridge := bridge.NewNews(ns, nm, logger)
// Add bridges to QML.
qmlWidget.RootContext().SetContextProperty("diablo", diabloBridge)
diabloBridge.Connect()
qmlWidget.RootContext().SetContextProperty("settings", configBridge)
configBridge.Connect()
qmlWidget.RootContext().SetContextProperty("ladder", ladderBridge)
ladderBridge.Connect()
qmlWidget.RootContext().SetContextProperty("news", newsBridge)
newsBridge.Connect()
// Set build version on the bridge to inform the gui.
configBridge.SetBuildVersion(buildVersion)
// Make sure the window is allowed to minimize.
goqmlframeless.AllowMinimize(fw.WinId())
// Set the source for our drawable widget to our qml entrypoint.
if environment == "production" {
qmlWidget.SetSource(core.NewQUrl3("qrc:/qml/main.qml", 0))
} else {
// Allows for reloading QML without rebuilding, useful while developing.
qmlWidget.SetSource(core.NewQUrl3("qml/main.qml", 0))
}
fw.Show()
app.Exec()
}
// getConfigPath returns the target specific application data directory.
func getConfigPath() (string, error) {
locations := core.QStandardPaths_StandardLocations(
core.QStandardPaths__AppLocalDataLocation,
)
if len(locations) == 0 {
return "", errors.New("failed to locate application data directory")
}
// Grab the first available location.
return locations[0], nil
}
func populateGameModel(conf *storage.Config, gm *config.GameModel) {
for _, game := range conf.Games {
g := config.NewGame(nil)
g.ID = game.ID
g.Location = game.Location
g.Instances = game.Instances
g.OverrideBHCfg = game.OverrideBHCfg
g.Flags = game.Flags
g.HDVersion = game.HDVersion
g.MaphackVersion = game.MaphackVersion
gm.AddGame(g)
}
}
// enableDebugger will capture stdout and stderr output.
func enableDebugger(logger log.Logger) {
r, w, err := os.Pipe()
if err != nil {
os.Exit(0)
}
os.Stdout = w
os.Stderr = w
go func() {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Text()
logger.Debug(line)
}
}()
}
// envString extracts a string from os environment.
func envString(env, fallback string) string {
e := os.Getenv(env)
if e == "" {
return fallback
}
return e
}
// envBool extracts a bool from os environment.
func envBool(env string, fallback bool) bool {
e := os.Getenv(env)
if e == "" {
return fallback
}
v, err := strconv.ParseBool(e)
if err != nil {
return fallback
}
return v
}