feat(cli|ui): add ~~beautiful~~ useless UI when launching bot

This commit is contained in:
Romain J 2020-06-02 01:47:24 +02:00
parent 2e76379c87
commit 28d1d71c5a
10 changed files with 247 additions and 98 deletions

View file

@ -1,11 +1,15 @@
<component name="ProjectDictionaryState">
<dictionary name="romain">
<words>
<w>commandstats</w>
<w>ipinfo</w>
<w>iplocalise</w>
<w>localiseip</w>
<w>postgresql</w>
<w>socketstats</w>
<w>splt</w>
<w>tutux</w>
<w>webhooks</w>
</words>
</dictionary>
</component>

View file

@ -1,17 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="a3206292-bb22-4c8b-9df5-9120f30ba1d3" name="5ed033fd0a73a530ba05810d iplocalise" comment="">
<change beforePath="$PROJECT_DIR$/configs/bot/protected.py" beforeDir="false" afterPath="$PROJECT_DIR$/configs/bot/protected.py" afterDir="false" />
<list default="true" id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment="">
<change beforePath="$PROJECT_DIR$/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/app.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cogs/Logs.py" beforeDir="false" afterPath="$PROJECT_DIR$/cogs/Logs.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cogs/Network.py" beforeDir="false" afterPath="$PROJECT_DIR$/cogs/Network.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/configs/bot/settings.py.example" beforeDir="false" afterPath="$PROJECT_DIR$/configs/bot/settings.py.example" afterDir="false" />
<change beforePath="$PROJECT_DIR$/requirements.txt" beforeDir="false" afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/utils/functions/extra.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/functions/extra.py" afterDir="false" />
</list>
<list id="77afe056-bf99-4d17-ac12-b340599c2650" name="5ed03423d0f94b557e83cafb ping" comment="">
<list id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="">
<change beforePath="$PROJECT_DIR$/.idea/dictionaries/romain.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/dictionaries/romain.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/app.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/requirements.txt" beforeDir="false" afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
</list>
<list id="6566fca1-2e90-48bb-9e74-dd3badbaca99" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/.idea/discord.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/discord.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
@ -29,6 +31,27 @@
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="LineStatusTrackerManager">
<file path="$PROJECT_DIR$/app.py">
<ranges>
<range start1="8" end1="8" start2="8" end2="9" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="9" end1="10" start2="10" end2="10" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="12" end1="12" start2="12" end2="13" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="14" end1="14" start2="15" end2="16" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="16" end1="16" start2="18" end2="27" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="34" end1="35" start2="45" end2="48" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="41" end1="45" start2="54" end2="59" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="46" end1="48" start2="60" end2="60" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="52" end1="53" start2="64" end2="64" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="54" end1="57" start2="65" end2="66" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="62" end1="70" start2="71" end2="97" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="71" end1="72" start2="98" end2="99" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="100" end1="101" start2="127" end2="128" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="106" end1="115" start2="133" end2="144" changelist="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" />
<range start1="131" end1="132" start2="160" end2="161" changelist="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" />
</ranges>
</file>
</component>
<component name="ProjectId" id="1c8uTCADTYzyrek4IjGPAZUYsa9" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="1" id="Add" />
@ -42,20 +65,23 @@
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/cogs" />
<property name="last_opened_file_path" value="/Volumes/Cache/tmp/Red-DiscordBot" />
<property name="node.js.detected.package.eslint" value="true" />
<property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.path.for.package.eslint" value="project" />
<property name="node.js.path.for.package.tslint" value="project" />
<property name="node.js.selected.package.eslint" value="(autodetect)" />
<property name="node.js.selected.package.tslint" value="(autodetect)" />
<property name="settings.editor.selected.configurable" value="preferences.startup.tasks" />
<property name="settings.editor.selected.configurable" value="reference.settings.ide.settings.uml" />
<property name="tasks.open.task.update.state.enabled" value="false" />
</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/cogs" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/utils/locales" />
<recent name="$PROJECT_DIR$/cogs" />
<recent name="$PROJECT_DIR$/configs/bot" />
</key>
@ -69,7 +95,7 @@
<created>1589922546510</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1590880224598</updated>
<updated>1590958395349</updated>
<workItem from="1589922559463" duration="2090000" />
<workItem from="1589925987600" duration="7107000" />
<workItem from="1589991138257" duration="2797000" />
@ -88,27 +114,29 @@
<workItem from="1590755733508" duration="16000" />
<workItem from="1590878235258" duration="1205000" />
<workItem from="1590880221861" duration="3000" />
<workItem from="1590958284823" duration="111000" />
</task>
<task id="5ed03423d0f94b557e83cafb" summary="ping">
<changelist id="77afe056-bf99-4d17-ac12-b340599c2650" name="5ed03423d0f94b557e83cafb ping" comment="" />
<task id="5ed41911b012e33f68a07e7a" summary="i18n">
<changelist id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="" />
<created>1591054207986</created>
<option name="issue" value="true" />
<url>https://trello.com/c/lpMrzLET/17-ping</url>
<option name="number" value="17" />
<option name="presentableId" value="5ed03423d0f94b557e83cafb" />
<updated>1590880232278</updated>
<workItem from="1590879444660" duration="777000" />
<workItem from="1590880224862" duration="8000" />
<url>https://trello.com/c/vK0cBbF2/38-i18n</url>
<option name="number" value="38" />
<option name="presentableId" value="5ed41911b012e33f68a07e7a" />
<updated>1591049955763</updated>
<workItem from="1590958395790" duration="2831000" />
<workItem from="1591015705338" duration="610000" />
<workItem from="1591040701796" duration="3916000" />
</task>
<task active="true" id="5ed033fd0a73a530ba05810d" summary="iplocalise">
<changelist id="a3206292-bb22-4c8b-9df5-9120f30ba1d3" name="5ed033fd0a73a530ba05810d iplocalise" comment="" />
<task active="true" id="5ed57ed9960f35191182a924" summary="core">
<changelist id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment="" />
<created>1591054207986</created>
<option name="issue" value="true" />
<url>https://trello.com/c/A5f7QCk2/11-iplocalise</url>
<option name="number" value="11" />
<option name="presentableId" value="5ed033fd0a73a530ba05810d" />
<updated>1590880232278</updated>
<workItem from="1590880232865" duration="2379000" />
<workItem from="1590938725549" duration="4995000" />
<workItem from="1590957507554" duration="497000" />
<url>https://trello.com/c/SafaMBht/40-core</url>
<option name="number" value="40" />
<option name="presentableId" value="5ed57ed9960f35191182a924" />
<updated>1591049955763</updated>
<workItem from="1591049956280" duration="4910000" />
</task>
<option name="localTasksCounter" value="2" />
<option name="createBranch" value="false" />
@ -148,22 +176,22 @@
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2629" y="379" width="462" height="333" key="#com.intellij.tools.ToolEditorDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590878943253" />
<state x="2663" y="313" width="428" height="484" key="FileChooserDialogImpl" timestamp="1590755745934">
<state x="2663" y="313" width="428" height="484" key="FileChooserDialogImpl" timestamp="1591044999557">
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2663" y="313" width="428" height="484" key="FileChooserDialogImpl/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590755745934" />
<state x="2663" y="313" width="428" height="484" key="FileChooserDialogImpl/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1591044999557" />
<state x="2666" y="239" width="421" height="633" key="RollbackChangesDialog" timestamp="1589983513390">
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2666" y="239" width="421" height="633" key="RollbackChangesDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983513390" />
<state x="2362" y="183" key="SettingsEditor" timestamp="1590879331835">
<state x="2362" y="183" key="SettingsEditor" timestamp="1590959187656">
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2362" y="183" key="SettingsEditor/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590879331835" />
<state x="2656" y="388" width="499" height="366" key="SimpleOpenTaskDialog" timestamp="1590880232304">
<state x="2362" y="183" key="SettingsEditor/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590959187656" />
<state x="2656" y="388" width="499" height="366" key="SimpleOpenTaskDialog" timestamp="1591049955869">
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2656" y="388" width="499" height="366" key="SimpleOpenTaskDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590880232304" />
<state x="2656" y="388" width="499" height="366" key="SimpleOpenTaskDialog/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1591049955869" />
<state x="2727" y="471" width="299" height="169" key="VCS.ChangelistChooser" timestamp="1589983445998">
<screen x="1920" y="0" width="1920" height="1080" />
</state>
@ -192,10 +220,10 @@
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2527" y="274" width="700" height="530" key="recent.locations.popup/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1589983638292" />
<state x="2543" y="261" width="672" height="678" key="search.everywhere.popup" timestamp="1590943531475">
<state x="2543" y="261" width="672" height="678" key="search.everywhere.popup" timestamp="1591052733133">
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2543" y="261" width="672" height="678" key="search.everywhere.popup/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590943531475" />
<state x="2543" y="261" width="672" height="678" key="search.everywhere.popup/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1591052733133" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>

93
app.py
View file

@ -6,14 +6,25 @@ from typing import List
import aiohttp
import discord
from colorama import Fore, Style, init
from discord.ext import commands
from tortoise import Tortoise
from configs.bot import settings
from utils.functions.cli import bordered
from utils.functions.extra import ContextPlus, get_prefix, \
get_owners, get_blacklist
from version import __version__
log = logging.getLogger(__name__)
init()
NAME = r"""
_____ _ _ _ _
|_ _| ___ _| |__ ___ | |_ | |__ ___ | |_
| || | | \ \/ / '_ \ / _ \| __|____| '_ \ / _ \| __|
| || |_| |> <| |_) | (_) | ||_____| |_) | (_) | |_
|_| \__,_/_/\_\_.__/ \___/ \__| |_.__/ \___/ \__|
"""
l_extensions: List[str] = [
"jishaku",
@ -32,44 +43,60 @@ class TuxBot(commands.AutoShardedBot):
def __init__(self):
self.uptime = datetime.datetime.utcnow()
self.config = settings
self._config = settings
self.locale = self._config.default_locale
super().__init__(
command_prefix=get_prefix,
case_insensitive=True
)
self.logs_channels = {
"dm": self.config.logs["dm"],
"mentions": self.config.logs["mentions"],
"guilds": self.config.logs["guilds"],
"errors": self.config.logs["errors"],
"dm": self._config.logs["dm"],
"mentions": self._config.logs["mentions"],
"guilds": self._config.logs["guilds"],
"errors": self._config.logs["errors"],
"gateway": self._config.logs["gateway"],
}
print("\n"*2)
for extension in l_extensions:
try:
self.load_extension(extension)
print(extension, "loaded !")
except Exception as e:
print(f"{type(e).__name__ }:", e)
print("\n"*2)
log.warning(f"{type(e).__name__}: {e}")
async def is_owner(self, user: discord.User):
return user.id in get_owners()
async def on_ready(self):
print(f"Connected !\n"
f"\n"
f"==> info: bot username {self.user}\n"
f" info: bot id {self.user.id}\n"
f" info: bot prefix {self.command_prefix}\n"
f"==> info: guild count {len(self.guilds)}\n"
f" info: member count {len(list(self.get_all_members()))}\n"
f" info: channel count {len(list(self.get_all_channels()))}")
INFO = {
'title': "INFO",
'rows': [
str(self.user),
f"Prefixes: {', '.join(self._config.prefixes)}",
f"Language: {self.locale}",
f"Tuxbot Version: {__version__}",
f"Discord.py Version: {discord.__version__}",
f"Shards: {self.shard_count}",
f"Servers: {len(self.guilds)}",
f"Users: {len(self.users)}"
]
}
print(f"\n{'='*118}\n\n")
COGS = {
'title': "COGS",
'rows': []
}
for extension in l_extensions:
COGS['rows'].append(
f"[{'X' if extension in self.extensions else ' '}] {extension}"
)
print(Fore.LIGHTBLUE_EX + NAME)
print(Style.RESET_ALL)
print(bordered(INFO, COGS))
print(f"\n{'=' * 118}\n\n")
async def on_resumed(self):
print(f"resumed... {self.uptime}")
@ -98,21 +125,23 @@ class TuxBot(commands.AutoShardedBot):
async def bot_start(self):
self.session = aiohttp.ClientSession(loop=self.loop)
await self.login(self.config.token, bot=True)
await self.login(self._config.token, bot=True)
await self.connect()
def run(self):
loop = self.loop
loop.run_until_complete(Tortoise.init(
db_url=self.config.postgresql,
modules={
"models": [
"models.__init__"
]
}
))
loop.run_until_complete(Tortoise.generate_schemas())
# loop.run_until_complete(
# Tortoise.init(
# db_url=self._config.postgresql,
# modules={
# "models": [
# "models.__init__"
# ]
# }
# )
# )
# loop.run_until_complete(Tortoise.generate_schemas())
try:
loop.run_until_complete(self.bot_start())
@ -129,7 +158,7 @@ def setup_logging():
logger.setLevel(logging.INFO)
try:
handler = logging.FileHandler(filename='logs/tuxbot.log',
handler = logging.FileHandler(filename='tuxbot.log',
encoding='utf-8', mode='w')
fmt = logging.Formatter('[{levelname:<7}] [{asctime}]'
' {name}: {message}',

View file

@ -293,7 +293,8 @@ class Logs(commands.Cog):
total = sum(self.bot.socket_stats.values())
cpm = total / minutes
await ctx.send(
f'{total} socket events observed ({cpm:.2f}/minute):\n{self.bot.socket_stats}')
f'{total} socket events observed ({cpm:.2f}/minute):\n'
f'{self.bot.socket_stats}')
@commands.command('uptime')
async def _uptime(self, ctx):

View file

@ -60,7 +60,7 @@ class Network(commands.Cog, name="Useless"):
ip_info = obj.lookup()
try:
handler = ipinfo.getHandler(self.bot.config.ipinfo)
handler = ipinfo.getHandler(self.bot._config.ipinfo)
details = handler.getDetails(target)
api_result = True
except (RequestQuotaExceededError, HTTPError):

View file

@ -1,5 +1,6 @@
token = ""
prefix = "drw."
prefixes = ["drw."]
default_locale = "en-US"
main_guild = int

View file

@ -1,28 +1,11 @@
aiofiles==0.5.0
aiohttp==3.6.2
aiosqlite==0.13.0
astunparse==1.6.3
async-timeout==3.0.1
# asyncpg==0.20.1
attrs==19.3.0
braceexpand==0.1.5
chardet==3.0.4
ciso8601==2.1.3
discord-flags==2.1.1
discord.py==1.3.3
humanize==2.4.0
idna==2.9
import-expression==1.1.2
jishaku==1.18.2.188
mpmath==1.1.0
multidict==4.7.6
Pillow==7.1.2
psutil==5.7.0
PyPika==0.37.6
six==1.14.0
# tortoise-orm==0.16.11
typing-extensions==3.7.4.2
websockets==8.1
yarl==1.4.2
ipinfo==3.0.0
ipwhois==1.1.0
discord.py
discord-flags
asyncpg
tortoise-orm
requests
ipinfo
ipwhois
humanize
psutil
aiohttp
colorama

89
utils/functions/cli.py Normal file
View file

@ -0,0 +1,89 @@
import codecs
import itertools
import sys
def bordered(*columns: dict) -> str:
"""
credits to https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/develop/redbot/core/utils/chat_formatting.py
Get two blocks of text in a borders.
Note
----
This will only work with a monospaced font.
Parameters
----------
*columns : `sequence` of `str`
The columns of text, each being a list of lines in that column.
Returns
-------
str
The bordered text.
"""
encoder = codecs.getencoder(sys.stdout.encoding)
try:
encoder("┌┐└┘─│") # border symbols
except UnicodeEncodeError:
ascii_border = True
else:
ascii_border = False
borders = {
"TL": "+" if ascii_border else "", # Top-left
"TR": "+" if ascii_border else "", # Top-right
"BL": "+" if ascii_border else "", # Bottom-left
"BR": "+" if ascii_border else "", # Bottom-right
"HZ": "-" if ascii_border else "", # Horizontal
"VT": "|" if ascii_border else "", # Vertical
}
sep = " " * 4 # Separator between boxes
widths = tuple(
max(
len(row) for row in column.get('rows')
) + 9
for column in columns
) # width of each col
cols_done = [False] * len(columns) # whether or not each column is done
lines = [""]
for i, column in enumerate(columns):
lines[0] += "{TL}" + "{HZ}" + column.get('title') \
+ "{HZ}" * (widths[i] - len(column.get('title')) - 1) \
+ "{TR}" + sep
for line in itertools.zip_longest(
*[column.get('rows') for column in columns]
):
row = []
for colidx, column in enumerate(line):
width = widths[colidx]
done = cols_done[colidx]
if column is None:
if not done:
# bottom border of column
column = "{HZ}" * width
row.append("{BL}" + column + "{BR}")
cols_done[colidx] = True # mark column as done
else:
# leave empty
row.append(" " * (width + 2))
else:
column += " " * (width - len(column)) # append padded spaces
row.append("{VT}" + column + "{VT}")
lines.append(sep.join(row))
final_row = []
for width, done in zip(widths, cols_done):
if not done:
final_row.append("{BL}" + "{HZ}" * width + "{BR}")
else:
final_row.append(" " * (width + 2))
lines.append(sep.join(final_row))
return "\n".join(lines).format(**borders)

View file

@ -7,7 +7,7 @@ import discord
from discord.ext import commands, flags
from configs.bot.protected import protected
from configs.bot.settings import prefix
from configs.bot.settings import prefixes
class ContextPlus(commands.Context):
@ -89,7 +89,7 @@ def group_extra(*args, **kwargs):
async def get_prefix(bot, message):
custom_prefix = [prefix]
custom_prefix = prefixes
if message.guild:
path = f"configs/guilds/{str(message.guild.id)}.json"

14
version.py Normal file
View file

@ -0,0 +1,14 @@
import subprocess
from collections import namedtuple
build = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'])\
.decode()
VersionInfo = namedtuple('VersionInfo', 'major minor micro releaselevel build')
version_info = VersionInfo(
major=3, minor=0, micro=0,
releaselevel='alpha', build=build
)
__version__ = "v{}.{}.{}"\
.format(version_info.major, version_info.minor, version_info.micro)