forked from CactusDev/CactusBot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cactus.py
209 lines (162 loc) · 6.23 KB
/
cactus.py
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
# CactusBot!
from messages import MessageHandler
from beam import Beam
from models import Base, engine
from json import load, dump
from os.path import exists
from shutil import copyfile
from functools import reduce, partial
from tornado.ioloop import IOLoop
from tornado.autoreload import add_reload_hook, watch, start
from traceback import format_exc
from time import sleep
from argparse import ArgumentParser
cactus_art = r"""CactusBot initialized!
,`""',
;' ` ;
;`,',;
;' ` ;
,,, ;`,',; _____ _
;,` ; ;' ` ; ,', / ____| | |
;`,'; ;`,',; ;,' ; | | __ _ ___| |_ _ _ ___
;',`; ;` ' ; ;`'`'; | | / _` |/ __| __| | | / __|
;` '',''` `,',`',; | |___| (_| | (__| |_| |_| \__ \
`''`'; ', ;`'`' \_____\__,_|\___|\__|\__,_|___/
;' `';
;` ' ;
;' `';
;` ' ;
; ',';
;,' ';
Made by: 2Cubed, Innectic, and ParadigmShift3d
"""
class Cactus(MessageHandler, Beam):
started = False
connected = False
def __init__(self, **kwargs):
super(Cactus, self).__init__(**kwargs)
self.debug = kwargs.get("debug", False)
self.config_file = kwargs.get("config_file", "data/config.json")
self.database = kwargs.get("database", "data/data.db")
self.quiet = kwargs.get("quiet", False)
self.no_messages = kwargs.get("no_messages", False)
def _init_database(self, database):
"""Ensure the database exists."""
if exists(database):
self.logger.info("Found database.")
else:
self.logger.info("Database wasn't found.")
self.logger.info("Creating and setting defaults...")
Base.metadata.create_all(engine)
self.logger.info("Done!")
def load_config(self, filename):
"""Load configuration file."""
if exists(filename):
self.logger.info("Configuration file found. Loading...")
self.config_file = filename
with open(filename) as config:
self.config = load(config)
return self.config
else:
self.logger.warn("Configuration file was not found. Creating...")
copyfile("data/config-template.json", filename)
self.logger.error(
"Configuration file created. Please enter values and restart.")
raise FileNotFoundError("Configuration file not found.")
exit()
def update_config(self, keys, value):
"""Update configuration file value."""
with open(self.config_file, 'r') as config:
config_data = load(config)
reduce(lambda d, k: d[k], keys.split('.')[:-1], config_data)[
keys.split('.')[-1]] = value
with open(self.config_file, 'w+') as config:
dump(config_data, config, indent=2, sort_keys=True)
self.config = config_data
return self.config
def run(self, *args, **kwargs):
"""Run bot."""
self.logger.info(cactus_art)
self._init_database(self.database)
self.load_config(filename=self.config_file)
self.started = True
while self.config.get("autorestart") or not self.started:
try:
self.bot_data = self.login(**self.config["auth"])
self.bot_name = self.config["auth"]["username"]
self.logger.info("Authenticated as: {}.".format(
self.bot_data["username"]))
self.channel = self.config["channel"]
self.channel_data = self.get_channel(self.channel)
self._init_commands()
self._init_users()
self.connect(
self.channel_data["id"],
self.bot_data["id"],
quiet=self.quiet)
def connect_liveloading():
try:
self.connect_to_constellation(
self.channel_data["id"],
self.channel_data["userId"])
except ConnectionError as e:
self.logger.warning("Caught ConnectionError!")
self.logger.warning("Reconnecting to liveloading")
self.logger.warning(e)
connect_liveloading()
connect_liveloading()
if str(self.debug).lower() in ("true", "debug"):
add_reload_hook(partial(
self.send_message,
"Restarting, thanks to debug mode. :spaceship"
))
watch(self.config_file)
start(check_time=5000)
IOLoop.instance().start()
except KeyboardInterrupt:
print()
self.logger.info("Removing thorns... done.")
try:
self.send_message("CactusBot deactivated! :cactus")
except Exception:
pass
finally:
exit()
except Exception:
self.logger.critical("Oh no, I crashed!")
try:
self.send_message("Oh no, I crashed! :127")
except Exception:
pass
self.logger.error('\n\n' + format_exc())
if self.config.get("autorestart"):
self.logger.info("Restarting in 10 seconds...")
try:
sleep(10)
except KeyboardInterrupt:
self.logger.info("CactusBot deactivated.")
exit()
else:
self.logger.info("CactusBot deactivated.")
exit()
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument(
"--quiet",
help="send no messages to public chat",
metavar="USER",
nargs='?',
const=True,
default=False
)
parser.add_argument(
"--debug",
help="set custom logger level",
metavar="LEVEL",
nargs='?',
const=True,
default="info"
)
parsed = parser.parse_args()
cactus = Cactus(**parsed.__dict__)
cactus.run()