Passed
Pull Request — stable (#69)
by Sydney
01:17
created

botutils.convert_size()   A

Complexity

Conditions 2

Size

Total Lines 8
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nop 1
1
#    Copyright 2017 Starbot Discord Project
2
# 
3
#    Licensed under the Apache License, Version 2.0 (the "License");
4
#    you may not use this file except in compliance with the License.
5
#    You may obtain a copy of the License at
6
# 
7
#        http://www.apache.org/licenses/LICENSE-2.0
8
# 
9
#    Unless required by applicable law or agreed to in writing, software
10
#    distributed under the License is distributed on an "AS IS" BASIS,
11
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
#    See the License for the specific language governing permissions and
13
#    limitations under the License.
14
15
import math
16
import os
17
import platform
18
import sys
19
import time
20
21
import discord
22
import psutil
23
import pyspeedtest
24
25
from api import settings, logging, command, message, plugin, git
26
from api.bot import Bot
27
from libs import progressBar, readableTime, displayname
28
29
# Command names.
30
SERVERSCMD = "servers"
31
NICKNAMECMD = "nickname"
32
33
def commands_detect_dups():
34
    duplicates = []
35
    commands_list = []
36
    for plugin_in in Bot.plugins:
37
        for command_in in plugin_in.commands:
38
            commands_list.append(command_in.name)
39
40
    for command_in in commands_list:
41
        commandOccurances = 0
42
        for command2 in commands_list:
43
            if command_in == command2:
44
                commandOccurances += 1
45
        if commandOccurances > 1:
46
            duplicates.append(command_in)
47
48
    return list(set(duplicates))
49
50
def convert_size(size_bytes: int) -> str:
51
    if size_bytes == 0:
52
        return '0B'
53
    size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
54
    i = int(math.floor(math.log(size_bytes, 1024)))
55
    p = math.pow(1024, i)
56
    s = round(size_bytes/p, 2)
57
    return '%s %s' % (s, size_name[i])
58
59
def onInit(plugin_in: plugin.Plugin):
60
    plugins_command    = command.Command(plugin_in, 'plugins', shortdesc='Print a list of plugins', devcommand=True)
61
    commands_command   = command.Command(plugin_in, 'commands', shortdesc='Print a list of commands', devcommand=True)
62
    help_command       = command.Command(plugin_in, 'help', shortdesc='Print a list of commands')
63
    info_command       = command.Command(plugin_in, 'info', shortdesc='Print some basic bot info')
64
    plugintree_command = command.Command(plugin_in, 'plugintree', shortdesc='Print a tree of plugins and commands', devcommand=True)
65
    uptime_command     = command.Command(plugin_in, 'uptime', shortdesc='Print the bot\'s uptime', devcommand=True)
66
    hostinfo_command   = command.Command(plugin_in, 'hostinfo', shortdesc='Prints information about the bots home', devcommand=True)
67
    cpuinfo_command    = command.Command(plugin_in, 'cpuinfo', shortdesc='Prints info about the system CPUs', devcommand=True)
68
    setprefix_command  = command.Command(plugin_in, 'setprefix', shortdesc='Set the server prefix', devcommand=True)
69
    getprefix_command  = command.Command(plugin_in, 'getprefix', shortdesc='Get the server prefix', devcommand=True)
70
    speedtest_command  = command.Command(plugin_in, 'speedtest', shortdesc='Run a speedtest', devcommand=True)
71
    addowner_command   = command.Command(plugin_in, 'addowner', shortdesc='Add a bot owner', devcommand=True)
72
    owners_command     = command.Command(plugin_in, 'owners', shortdesc='Print the bot owners', devcommand=True)
73
    return plugin.Plugin(plugin_in, 'botutils', [plugins_command, commands_command, help_command, info_command, plugintree_command, uptime_command,
74
                                                 hostinfo_command, cpuinfo_command, setprefix_command, getprefix_command, speedtest_command, addowner_command,
75
                                                 owners_command])
76
77
async def onCommand(message_in):
78
    if message_in.command == 'plugins':
79
        plugin_list = []
80
        for plugin_in in Bot.plugins:
81
            plugin_list.append(plugin_in.name)
82
        return message.Message(body='```{}```'.format(', '.join(plugin_list)))
83
84
    if message_in.command == 'commands' or message_in.command == 'help':
85
        cmd_names = []
86
        cmd_descs = []
87
        for botcommand in Bot.commands:
88
            if botcommand.devcommand != True:
89
                cmd_names.append(botcommand.name)
90
                cmd_descs.append(botcommand.shortdesc)
91
        cmd_list = []
92
        pad_len = len(max(cmd_names, key=len))
93
        for index, value in enumerate(cmd_names):
94
            cmd_list.append('{} - {}'.format(cmd_names[index].ljust(pad_len), cmd_descs[index]))
95
        return message.Message(body='```{}```'.format('\n'.join(cmd_list)))
96
97
    if message_in.command == 'info':
98
        sha = git.git_commit()
99
        track = git.git_branch()
100
        remote = git.get_remote()
101
        link = git.get_url()
102
        if track == 'master':
103
            embed = discord.Embed(color=discord.Color.red())
104
        elif track == 'unstable':
105
            embed = discord.Embed(color=discord.Color.gold())
106
        elif track == 'stable':
107
            embed = discord.Embed(color=discord.Color.green())
108
        else:
109
            embed = discord.Embed(color=discord.Color.light_grey())
110
        embed.set_author(name='Project StarBot v0.2.0-{} on track {}'.format(sha[:7], track))
111
        embed.set_footer(text="Pulled from {}".format(remote))
112
        return message.Message(embed=embed)
113
114
    if message_in.command == 'plugintree':
115
        dups = commands_detect_dups()
116
        plugin_string = '```\n'
117
        for plugin_in in Bot.plugins:
118
            plugin_string += '{}\n'.format(plugin_in.name)
119
            plugin_commands = len(plugin_in.commands)
120
            index = 0
121
            for command_in in plugin_in.commands:
122
                index += 1
123
                if plugin_commands != index:
124
                    if command_in.name in dups:
125
                        plugin_string += '├ {} <-- duplicate\n'.format(command_in.name)
126
                    else:
127
                        plugin_string += '├ {}\n'.format(command_in.name)
128
                else:
129
                    if command_in.name in dups:
130
                        plugin_string += '└ {} <-- duplicate\n'.format(command_in.name)
131
                    else:
132
                        plugin_string += '└ {}\n'.format(command_in.name)
133
        plugin_string += '```'
134
        return message.Message(body=plugin_string)
135
136
    if message_in.command == 'uptime':
137
        time_current = int(time.time())
138
        time_str = readableTime.getReadableTimeBetween(Bot.startTime, time_current)
139
        return message.Message(body='I\'ve been up for *{}*.'.format(time_str))
140
141
    if message_in.command == 'hostinfo':
142
        # Get information about host environment.
143
        time_current = int(time.time())
144
145
        # CPU stats.
146
        cpu_threads = os.cpu_count()
147
        cpu_usage = psutil.cpu_percent(interval=1)
148
149
        # Memory stats.
150
        mem_stats = psutil.virtual_memory()
151
        mem_percent = mem_stats.percent
152
        mem_used = convert_size(mem_stats.used)
153
        mem_total = convert_size(mem_stats.total)
154
155
        # Platform info.
156
        platform_current = platform.platform()
157
158
        # Python version info.
159
        pyver_major = sys.version_info.major
160
        pyver_minor = sys.version_info.minor
161
        pyver_micro = sys.version_info.micro
162
        pyver_release = sys.version_info.releaselevel
163
164
        # Storage info.
165
        stor = psutil.disk_usage('/')
166
        stor_used = convert_size(stor.used)
167
        stor_total = convert_size(stor.total)
168
        stor_free = convert_size(stor.total - stor.used)
169
170
        # Format hostinfo with OS, CPU, RAM, storage, and other bot info.
171
        msg = '***{}\'s*** **Home:**\n'.format(displayname.name(message_in.guild.me))
172
        msg += '```Host OS       : {}\n'.format(platform_current)
173
        msg += 'Host Python   : {}.{}.{} {}\n'.format(pyver_major, pyver_minor, pyver_micro, pyver_release)
174
        if not isinstance(cpu_threads, int):
175
            msg += 'Host CPU usage: {}% of {}\n'.format(cpu_usage, platform.machine())
176
        elif cpu_threads > 1:
177
            msg += 'Host CPU usage: {}% of {} ({} threads)\n'.format(cpu_usage, platform.machine(), cpu_threads)
178
        else:
179
            msg += 'Host CPU usage: {}% of {} ({} thread)\n'.format(cpu_usage, platform.machine(), cpu_threads)
180
        msg += 'Host RAM      : {} ({}%) of {}\n'.format(mem_used, mem_percent, mem_total)
181
        msg += 'Host storage  : {} ({}%) of {} - {} free\n'.format(stor_used, stor.percent, stor_total, stor_free)
182
        msg += 'Hostname      : {}\n'.format(platform.node())
183
        msg += 'Host uptime   : {}```'.format(readableTime.getReadableTimeBetween(psutil.boot_time(), time.time()))
184
185
        # Return completed message.
186
        return message.Message(body=msg)
187
188
    if message_in.command == 'cpuinfo':
189
        # Get CPU usage and create string for message.
190
        cpu_pcts = psutil.cpu_percent(interval=0.1, percpu=True)
191
        cpu_pct_str = '{}\n'.format(platform.processor())
192
        cpu_threads = psutil.cpu_count()
193
        cpu_cores = psutil.cpu_count(logical=False)
194
        cpu_arch = platform.machine()
195
        # First, check to see if we can accurately determine the number of physical cores. If not, omit the core count.
196
        if not cpu_cores:
197
            if cpu_threads > 1:
198
                cpu_pct_str += '{} threads of {}'.format(cpu_threads, cpu_arch)
199
            else:
200
                cpu_pct_str += '{} thread of {}'.format(cpu_threads, cpu_arch)
201
        elif cpu_cores > 1: # Multiple cores.
202
            cpu_pct_str += '{} threads - {} cores of {}'.format(cpu_threads, cpu_cores, cpu_arch)
203
        else:
204
            if psutil.cpu_count() > 1: # Multiple threads, single core.
205
                cpu_pct_str += '{} threads - {} core of {}'.format(cpu_threads, cpu_cores, cpu_arch)
206
            else: # Single thread, single core.
207
                cpu_pct_str += '{} thread - {} core of {}'.format(cpu_threads, cpu_cores, cpu_arch)
208
209
        # Build CPU usage graph.
210
        cpu_pct_str += '\n\n'
211
        for index, value in enumerate(cpu_pcts):
212
            cpu_pct_str += 'CPU {}: {}\n'.format(str(index), progressBar.makeBar(cpu_pcts[index]))
213
214
        # Return completed message.
215
        return message.Message(body='```{}```'.format(cpu_pct_str))
216
217
    if message_in.command == 'setprefix':
218
        if settings.owners_check(message_in.author.id):
219
            prefix = message_in.body.split(' ', 1)[-1]
220
            settings.prefix_set(message_in.guild.id, prefix)
221
            return message.Message(body='Prefix set to {}'.format(prefix))
222
        else:
223
            return message.Message(body='Only my owner can set the prefix!')
224
225
    if message_in.command == 'getprefix':
226
        return message.Message(body='Prefix is {}'.format(settings.prefix_get(message_in.guild.id)))
227
228
    if message_in.command == 'speedtest':
229
        if settings.owners_check(message_in.author.id):
230
            speed = pyspeedtest.SpeedTest()
231
            msg = '**Speed Test Results:**\n'
232
            msg += '```\n'
233
            msg += '    Ping: {}\n'.format(round(speed.ping(), 2))
234
            msg += 'Download: {}MB/s\n'.format(round(speed.download()/1024/1024, 2))
235
            msg += '  Upload: {}MB/s```'.format(round(speed.upload()/1024/1024, 2))
236
            return message.Message(body=msg)
237
        else:
238
            return message.Message(body='You do not have permisison to run a speedtest.')
239
240
    if message_in.command == "addowner":
241
        if settings.owners_get():
242
            try:
243
                if settings.owners_check(message_in.author.id):
244
                    member = message_in.body.strip()
245
                    new_member = displayname.memberForName(member, message_in.guild.members, message_in.guild.me)
246
247
                    if settings.owners_check(new_member.id):
248
                        return message.Message(body="User is already an owner.")
249
                    elif new_member.bot:
250
                        return message.Message(body="Bots cannot be owners.")
251
                    else:
252
                        settings.owners_add(new_member.id)
253
                        return message.Message(body="Added owner successfully.")
254
                else:
255
                    return message.Message(body="You aren't an owner of the bot.")
256
            except AttributeError:
257
                return message.Message(body="Invalid user.")
258
        else:
259
            settings.owners_add(message_in.author.id)
260
            return message.Message(body="You have successfully claimed yourself as the first owner!")
261
262
    if message_in.command == 'owners':
263
        owners = []
264
        if not settings.owners_get():
265
            return message.Message(body='I have no owners')
266
        for owner in settings.owners_get():
267
            user = displayname.memberForID(owner, message_in.guild.members, message_in.guild.me)
268
            if user:
269
                owners.append(str(user.name))
270
            else:
271
                owners.append(str(owner))
272
        owner_list = ', '.join(owners)
273
        return message.Message(body=owner_list)
274