-
Notifications
You must be signed in to change notification settings - Fork 138
/
config.go
203 lines (177 loc) · 5.5 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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package main
import (
"fmt"
"io"
"log"
"os"
"strconv"
"gopkg.in/yaml.v2"
)
type ConfigType struct {
Port int `yaml:"port"`
AltPort int `yaml:"alt_port"`
ProfilePort int `yaml:"profile_port"`
Scrollback int `yaml:"scrollback"`
DataDir string `yaml:"data_dir"`
KeyFile string `yaml:"key_file"`
Admins map[string]string `yaml:"admins"`
Censor bool `yaml:"censor,omitempty"`
Private bool `yaml:"private,omitempty"`
Allowlist map[string]string `yaml:"allowlist,omitempty"`
IntegrationConfig string `yaml:"integration_config"`
}
// IntegrationsType stores information needed by integrations.
// Code that uses this should check if fields are nil.
type IntegrationsType struct {
// Twitter stores the information needed for the Twitter integration.
// Check if it is enabled by checking if Twitter is nil.
Twitter *TwitterInfo `yaml:"twitter"`
// Slack stores the information needed for the Slack integration.
// Check if it is enabled by checking if Slack is nil.
Slack *SlackInfo `yaml:"slack"`
// Discord stores the information needed for the Discord integration.
// Check if it is enabled by checking if Discord is nil.
Discord *DiscordInfo `yaml:"discord"`
RPC *RPCInfo `yaml:"rpc"`
}
type TwitterInfo struct {
ConsumerKey string `yaml:"consumer_key"`
ConsumerSecret string `yaml:"consumer_secret"`
AccessToken string `yaml:"access_token"`
AccessTokenSecret string `yaml:"access_token_secret"`
}
type SlackInfo struct {
// Token is the Slack API token
Token string `yaml:"token"`
// ChannelID is the Slack channel to post to
ChannelID string `yaml:"channel_id"`
// Prefix is the prefix to prepend to messages from Slack when rendered for SSH users
Prefix string `yaml:"prefix"`
}
type DiscordInfo struct {
// Token is the Discord API token
Token string `yaml:"token"`
// ChannelID is the ID of the channel to post to
ChannelID string `yaml:"channel_id"`
// Prefix is the prefix to prepend to messages from Discord when rendered for SSH users
Prefix string `yaml:"prefix"`
// Compact mode disables avatars to save vertical space
CompactMode bool `yaml:"compact_mode"`
}
type RPCInfo struct {
Port int `yaml:"port"`
Key string `yaml:"key"`
}
var (
Config = ConfigType{ // first stores default config
Port: 2221,
AltPort: 8080,
ProfilePort: 5555,
Scrollback: 16,
DataDir: "devzat-data",
KeyFile: "devzat-sshkey",
IntegrationConfig: "",
}
Integrations = IntegrationsType{} // all nil
Log *log.Logger
)
func init() {
cfgFile := os.Getenv("DEVZAT_CONFIG")
if cfgFile == "" {
cfgFile = "devzat.yml"
}
errCheck := func(err error) {
if err != nil {
fmt.Println("err: " + err.Error())
os.Exit(0) // match `return` behavior
}
}
var d []byte
if _, err := os.Stat(cfgFile); err != nil {
if os.IsNotExist(err) {
fmt.Println("Config file not found, so using the default one and writing it to " + cfgFile)
d, err = yaml.Marshal(Config)
errCheck(err)
err = os.WriteFile(cfgFile, d, 0644)
}
errCheck(err)
} else {
d, err = os.ReadFile(cfgFile)
errCheck(err)
err = yaml.UnmarshalStrict(d, &Config)
errCheck(err)
fmt.Println("Config loaded from " + cfgFile)
}
err := os.MkdirAll(Config.DataDir, 0755)
errCheck(err)
logfile, err := os.OpenFile(Config.DataDir+string(os.PathSeparator)+"log.txt", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0666)
errCheck(err)
Log = log.New(io.MultiWriter(logfile, os.Stdout), "", log.Ldate|log.Ltime|log.Lshortfile)
if os.Getenv("PORT") != "" {
Config.Port, err = strconv.Atoi(os.Getenv("PORT"))
errCheck(err)
}
Backlog = make([]backlogMessage, Config.Scrollback)
if Config.IntegrationConfig != "" {
d, err = os.ReadFile(Config.IntegrationConfig)
errCheck(err)
err = yaml.UnmarshalStrict(d, &Integrations)
errCheck(err)
if Integrations.Slack != nil {
if Integrations.Slack.Prefix == "" {
Integrations.Slack.Prefix = "Slack"
}
if sl := Integrations.Slack; sl.Token == "" || sl.ChannelID == "" {
fmt.Println("error: Slack token or channel ID is missing")
os.Exit(0)
}
}
if Integrations.Discord != nil {
if Integrations.Discord.Prefix == "" {
Integrations.Discord.Prefix = "Discord"
}
if sl := Integrations.Discord; sl.Token == "" || sl.ChannelID == "" {
fmt.Println("error: Discord token or channel ID is missing")
os.Exit(0)
}
}
if Integrations.Twitter != nil {
if tw := Integrations.Twitter; tw.AccessToken == "" ||
tw.AccessTokenSecret == "" ||
tw.ConsumerKey == "" ||
tw.ConsumerSecret == "" {
fmt.Println("error: Twitter credentials are incomplete")
os.Exit(0)
}
}
fmt.Println("Integration config loaded from " + Config.IntegrationConfig)
if os.Getenv("DEVZAT_OFFLINE_SLACK") != "" {
fmt.Println("Disabling Slack")
Integrations.Slack = nil
}
if os.Getenv("DEVZAT_OFFLINE_DISCORD") != "" {
fmt.Println("Disabling Discord")
Integrations.Discord = nil
}
if os.Getenv("DEVZAT_OFFLINE_TWITTER") != "" {
fmt.Println("Disabling Twitter")
Integrations.Twitter = nil
}
if os.Getenv("DEVZAT_OFFLINE_RPC") != "" {
fmt.Println("Disabling RPC")
Integrations.RPC = nil
}
// Check for global offline for backwards compatibility
if os.Getenv("DEVZAT_OFFLINE") != "" {
fmt.Println("Offline mode")
Integrations.Slack = nil
Integrations.Discord = nil
Integrations.Twitter = nil
Integrations.RPC = nil
}
}
slackInit()
discordInit()
twitterInit()
rpcInit()
}