Switch to LF line endings
This commit is contained in:
parent
054970daa2
commit
813701c5db
25
API.md
25
API.md
@ -1,13 +1,12 @@
|
||||
## API
|
||||
|
||||
`discordmt` offers a simple API which other mods can use to listen to and send messages with Discord.
|
||||
|
||||
It does not expose the command interface or logins to the API, and `discord.register_on_message` events will *not* recieve login information.
|
||||
|
||||
### `discord.send(message [, optional id])`
|
||||
Sends `message` to Discord.
|
||||
This function makes an HTTP request; therefore the sending of large volumes of data might be better grouped into a single request. **Do note that Discord limits messages to 2,000 characters, and the relay automatically cuts off messages.**
|
||||
The optional `id` parameter specifies a specific Discord user to send the message to.
|
||||
|
||||
### `discord.register_on_message(function(name, message))`
|
||||
Adds a function to `discord.registered_on_messages`, which are called every time a message is received from Discord, excluding logins. `name` is by default the Discord username of the user who sent the message (excluding the discriminator) and `message` is the message content. This function should be called on startup.
|
||||
## API
|
||||
|
||||
`discordmt` offers a simple API which other mods can use to listen to and send messages with Discord.
|
||||
|
||||
It does not expose the command interface or logins to the API, and `discord.register_on_message` events will *not* recieve login information.
|
||||
|
||||
### `discord.send(message)`
|
||||
Sends `message` to Discord.
|
||||
This function makes an HTTP request; therefore the sending of large volumes of data might be better grouped into a single request. **Do note that Discord limits messages to 2,000 characters, and the relay automatically cuts off messages.**
|
||||
|
||||
### `discord.register_on_message(function(name, message))`
|
||||
Adds a function to `discord.registered_on_messages`, which are called every time a message is received from Discord, excluding logins. `name` is by default the Discord username of the user who sent the message (excluding the discriminator) and `message` is the message content. This function should be called on startup.
|
40
LICENSE.md
40
LICENSE.md
@ -1,21 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 archfan7411
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 archfan7411
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
118
README.md
118
README.md
@ -1,59 +1,59 @@
|
||||
## Minetest-Discord Relay `[discordmt]`
|
||||
|
||||
A feature-filled Discord relay for Minetest, supporting:
|
||||
|
||||
- Relaying server chat to Discord, and Discord chat to the server
|
||||
- Allowing anyone to get the server status via a command
|
||||
- Logging into the server from Discord *(configurable)*
|
||||
- Running commands from Discord *(configurable)*
|
||||
- A simple API
|
||||
|
||||
## Great! How do I use it?
|
||||
|
||||
Easy! `discordmt` works by running a Python program which converses with a serverside mod using HTTP requests. Don't have or want Python? No problem! Binaries are also available.
|
||||
|
||||
If you want to run the source, however, Python 3.6.3+, `aiohttp` 3.5+ and `discord.py` 1.2.0+ are required.
|
||||
|
||||
### Basic setup
|
||||
|
||||
1. Download the mod and binary executable (or the source code and its dependencies.)
|
||||
2. Create an application at the [Discord Developer Dashboard](https://discordapp.com/developers/applications/) and enable it as a bot (in the Bot tab.)
|
||||
3. Copy the token from your newly-created bot, and use it to finish setting up `relay.conf`.
|
||||
|
||||
Example `relay.conf`: *(The token shown below has been regenerated)*
|
||||
```
|
||||
[BOT]
|
||||
token = NjEwODk0MDU4ODY4NzAzMjMz.XVL5dA.8j8d2XN8_5UwRheG91P2XksYDoM
|
||||
command_prefix = !
|
||||
[RELAY]
|
||||
port = 8080
|
||||
channel_id = 576585506658189332
|
||||
allow_logins = true
|
||||
clean_invites = true
|
||||
use_nicknames = true
|
||||
```
|
||||
|
||||
4. Set `discord.port` in your `minetest.conf` to match the port you used in `relay.conf`. You may also set `discord.text_color` to a hex color string if you'd like to color relayed messages from Discord.
|
||||
|
||||
Example `minetest.conf` excerpt:
|
||||
```
|
||||
discord.port = 8080
|
||||
discord.text_color = #a7a7a7
|
||||
```
|
||||
*(Side note: The port must be set in both `relay.conf` and `minetest.conf` because users may decide to run the relay in a different location than the mod, or to run multiple relays/servers at once.)*
|
||||
|
||||
5. Run the relay and, when you're ready, the Minetest server. The relay may be left up even when the server goes down, or may run continuously between several server restarts, for maximum convenience.
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
**Q: I just want a normal relay. Can I disable logins?**
|
||||
A: Yep! Just set `allow_logins = false` in `relay.conf`.
|
||||
|
||||
**Q: Do I need to re-login after a server restart, like with the IRC mod?**
|
||||
A: Nope, logins persist as long as the relay is up.
|
||||
|
||||
**Q: I'm getting an HTTP error - it says the server can't be found?**
|
||||
A: Make sure the relay is running and that you've configured the correct port in both `minetest.conf` and `relay.conf`.
|
||||
|
||||
|
||||
|
||||
## Minetest-Discord Relay `[discordmt]`
|
||||
|
||||
A feature-filled Discord relay for Minetest, supporting:
|
||||
|
||||
- Relaying server chat to Discord, and Discord chat to the server
|
||||
- Allowing anyone to get the server status via a command
|
||||
- Logging into the server from Discord *(configurable)*
|
||||
- Running commands from Discord *(configurable)*
|
||||
- A simple API
|
||||
|
||||
## Great! How do I use it?
|
||||
|
||||
Easy! `discordmt` works by running a Python program which converses with a serverside mod using HTTP requests. Don't have or want Python? No problem! Binaries are also available.
|
||||
|
||||
If you want to run the source, however, Python 3.6.3+, `aiohttp` 3.5+ and `discord.py` 1.2.0+ are required.
|
||||
|
||||
### Basic setup
|
||||
|
||||
1. Download the mod and binary executable (or the source code and its dependencies.)
|
||||
2. Create an application at the [Discord Developer Dashboard](https://discordapp.com/developers/applications/) and enable it as a bot (in the Bot tab.)
|
||||
3. Copy the token from your newly-created bot, and use it to finish setting up `relay.conf`.
|
||||
|
||||
Example `relay.conf`: *(The token shown below has been regenerated)*
|
||||
```
|
||||
[BOT]
|
||||
token = NjEwODk0MDU4ODY4NzAzMjMz.XVL5dA.8j8d2XN8_5UwRheG91P2XksYDoM
|
||||
command_prefix = !
|
||||
[RELAY]
|
||||
port = 8080
|
||||
channel_id = 576585506658189332
|
||||
allow_logins = true
|
||||
clean_invites = true
|
||||
use_nicknames = true
|
||||
```
|
||||
|
||||
4. Set `discord.port` in your `minetest.conf` to match the port you used in `relay.conf`. You may also set `discord.text_color` to a hex color string if you'd like to color relayed messages from Discord.
|
||||
|
||||
Example `minetest.conf` excerpt:
|
||||
```
|
||||
discord.port = 8080
|
||||
discord.text_color = #a7a7a7
|
||||
```
|
||||
*(Side note: The port must be set in both `relay.conf` and `minetest.conf` because users may decide to run the relay in a different location than the mod, or to run multiple relays/servers at once.)*
|
||||
|
||||
5. Run the relay and, when you're ready, the Minetest server. The relay may be left up even when the server goes down, or may run continuously between several server restarts, for maximum convenience.
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
**Q: I just want a normal relay. Can I disable logins?**
|
||||
A: Yep! Just set `allow_logins = false` in `relay.conf`.
|
||||
|
||||
**Q: Do I need to re-login after a server restart, like with the IRC mod?**
|
||||
A: Nope, logins persist as long as the relay is up.
|
||||
|
||||
**Q: I'm getting an HTTP error - it says the server can't be found?**
|
||||
A: Make sure the relay is running and that you've configured the correct port in both `minetest.conf` and `relay.conf`.
|
||||
|
||||
|
||||
|
||||
|
280
init.lua
280
init.lua
@ -1,140 +1,140 @@
|
||||
local http = minetest.request_http_api()
|
||||
local settings = minetest.settings
|
||||
|
||||
local port = settings:get('discord.port') or 8080
|
||||
local timeout = 10
|
||||
|
||||
discord = {}
|
||||
|
||||
discord.text_colorization = settings:get('discord.text_color') or '#ffffff'
|
||||
|
||||
discord.registered_on_messages = {}
|
||||
|
||||
discord.register_on_message = function(func)
|
||||
table.insert(discord.registered_on_messages, func)
|
||||
end
|
||||
|
||||
local old_chat_send_all = minetest.chat_send_all
|
||||
|
||||
discord.handle_response = function(response)
|
||||
local data = response.data
|
||||
if data == '' or data == nil then
|
||||
return
|
||||
end
|
||||
local data = minetest.parse_json(response.data)
|
||||
if not data then
|
||||
return
|
||||
end
|
||||
if data.messages then
|
||||
for _, message in pairs(data.messages) do
|
||||
for _, func in pairs(discord.registered_on_messages) do
|
||||
func(message.author, message.content)
|
||||
end
|
||||
local msg = ('<%s@Discord> %s'):format(message.author, message.content)
|
||||
old_chat_send_all(minetest.colorize(discord.text_colorization, msg))
|
||||
minetest.log('[Discord] Message: '..msg)
|
||||
end
|
||||
end
|
||||
if data.commands then
|
||||
local commands = minetest.registered_chatcommands
|
||||
for _, v in pairs(data.commands) do
|
||||
if commands[v.command] then
|
||||
if minetest.get_ban_description(v.name) ~= '' then
|
||||
discord.send('You cannot run commands because you are banned.', v.context or nil)
|
||||
return
|
||||
end
|
||||
-- Check player privileges
|
||||
local required_privs = commands[v.command].privs or {}
|
||||
local player_privs = minetest.get_player_privs(v.name)
|
||||
for priv, value in pairs(required_privs) do
|
||||
if player_privs[priv] ~= value then
|
||||
discord.send('Insufficient privileges.', v.context or nil)
|
||||
return
|
||||
end
|
||||
end
|
||||
local old_chat_send_player = minetest.chat_send_player
|
||||
minetest.chat_send_player = function(name, message)
|
||||
old_chat_send_player(name, message)
|
||||
if name == v.name then
|
||||
discord.send(message, v.context or nil)
|
||||
end
|
||||
end
|
||||
success, ret_val = commands[v.command].func(v.name, v.params or '')
|
||||
if ret_val then
|
||||
discord.send(ret_val, v.context or nil)
|
||||
end
|
||||
minetest.chat_send_player = old_chat_send_player
|
||||
else
|
||||
discord.send(('Command not found: `%s`'):format(v.command), v.context or nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
if data.logins then
|
||||
local auth = minetest.get_auth_handler()
|
||||
for _, v in pairs(data.logins) do
|
||||
local authdata = auth.get_auth(v.username)
|
||||
local result = false
|
||||
if authdata then
|
||||
result = minetest.check_password_entry(v.username, authdata.password, v.password)
|
||||
end
|
||||
local request = {
|
||||
type = 'DISCORD_LOGIN_RESULT',
|
||||
user_id = v.user_id,
|
||||
username = v.username,
|
||||
success = result
|
||||
}
|
||||
http.fetch({
|
||||
url = 'localhost:'..tostring(port),
|
||||
timeout = timeout,
|
||||
post_data = minetest.write_json(request)
|
||||
}, discord.handle_response)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
discord.send = function(message, id)
|
||||
local data = {
|
||||
type = 'DISCORD-RELAY-MESSAGE',
|
||||
content = minetest.strip_colors(message)
|
||||
}
|
||||
if id then
|
||||
data['context'] = id
|
||||
end
|
||||
http.fetch({
|
||||
url = 'localhost:'..tostring(port),
|
||||
timeout = timeout,
|
||||
post_data = minetest.write_json(data)
|
||||
}, function(_) end)
|
||||
end
|
||||
|
||||
minetest.chat_send_all = function(message)
|
||||
old_chat_send_all(message)
|
||||
discord.send(message)
|
||||
end
|
||||
|
||||
minetest.register_on_chat_message(function(name, message)
|
||||
discord.send(('<%s> %s'):format(name, message))
|
||||
end)
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if dtime then
|
||||
timer = timer + dtime
|
||||
if timer > 0.2 then
|
||||
http.fetch({
|
||||
url = 'localhost:'..tostring(port),
|
||||
timeout = timeout,
|
||||
post_data = minetest.write_json({
|
||||
type = 'DISCORD-REQUEST-DATA'
|
||||
})
|
||||
}, discord.handle_response)
|
||||
timer = 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
discord.send('*** Server shutting down...')
|
||||
end)
|
||||
|
||||
discord.send('*** Server started!')
|
||||
local http = minetest.request_http_api()
|
||||
local settings = minetest.settings
|
||||
|
||||
local port = settings:get('discord.port') or 8080
|
||||
local timeout = 10
|
||||
|
||||
discord = {}
|
||||
|
||||
discord.text_colorization = settings:get('discord.text_color') or '#ffffff'
|
||||
|
||||
discord.registered_on_messages = {}
|
||||
|
||||
discord.register_on_message = function(func)
|
||||
table.insert(discord.registered_on_messages, func)
|
||||
end
|
||||
|
||||
local old_chat_send_all = minetest.chat_send_all
|
||||
|
||||
discord.handle_response = function(response)
|
||||
local data = response.data
|
||||
if data == '' or data == nil then
|
||||
return
|
||||
end
|
||||
local data = minetest.parse_json(response.data)
|
||||
if not data then
|
||||
return
|
||||
end
|
||||
if data.messages then
|
||||
for _, message in pairs(data.messages) do
|
||||
for _, func in pairs(discord.registered_on_messages) do
|
||||
func(message.author, message.content)
|
||||
end
|
||||
local msg = ('<%s@Discord> %s'):format(message.author, message.content)
|
||||
old_chat_send_all(minetest.colorize(discord.text_colorization, msg))
|
||||
minetest.log('[Discord] Message: '..msg)
|
||||
end
|
||||
end
|
||||
if data.commands then
|
||||
local commands = minetest.registered_chatcommands
|
||||
for _, v in pairs(data.commands) do
|
||||
if commands[v.command] then
|
||||
if minetest.get_ban_description(v.name) ~= '' then
|
||||
discord.send('You cannot run commands because you are banned.', v.context or nil)
|
||||
return
|
||||
end
|
||||
-- Check player privileges
|
||||
local required_privs = commands[v.command].privs or {}
|
||||
local player_privs = minetest.get_player_privs(v.name)
|
||||
for priv, value in pairs(required_privs) do
|
||||
if player_privs[priv] ~= value then
|
||||
discord.send('Insufficient privileges.', v.context or nil)
|
||||
return
|
||||
end
|
||||
end
|
||||
local old_chat_send_player = minetest.chat_send_player
|
||||
minetest.chat_send_player = function(name, message)
|
||||
old_chat_send_player(name, message)
|
||||
if name == v.name then
|
||||
discord.send(message, v.context or nil)
|
||||
end
|
||||
end
|
||||
success, ret_val = commands[v.command].func(v.name, v.params or '')
|
||||
if ret_val then
|
||||
discord.send(ret_val, v.context or nil)
|
||||
end
|
||||
minetest.chat_send_player = old_chat_send_player
|
||||
else
|
||||
discord.send(('Command not found: `%s`'):format(v.command), v.context or nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
if data.logins then
|
||||
local auth = minetest.get_auth_handler()
|
||||
for _, v in pairs(data.logins) do
|
||||
local authdata = auth.get_auth(v.username)
|
||||
local result = false
|
||||
if authdata then
|
||||
result = minetest.check_password_entry(v.username, authdata.password, v.password)
|
||||
end
|
||||
local request = {
|
||||
type = 'DISCORD_LOGIN_RESULT',
|
||||
user_id = v.user_id,
|
||||
username = v.username,
|
||||
success = result
|
||||
}
|
||||
http.fetch({
|
||||
url = 'localhost:'..tostring(port),
|
||||
timeout = timeout,
|
||||
post_data = minetest.write_json(request)
|
||||
}, discord.handle_response)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
discord.send = function(message, id)
|
||||
local data = {
|
||||
type = 'DISCORD-RELAY-MESSAGE',
|
||||
content = minetest.strip_colors(message)
|
||||
}
|
||||
if id then
|
||||
data['context'] = id
|
||||
end
|
||||
http.fetch({
|
||||
url = 'localhost:'..tostring(port),
|
||||
timeout = timeout,
|
||||
post_data = minetest.write_json(data)
|
||||
}, function(_) end)
|
||||
end
|
||||
|
||||
minetest.chat_send_all = function(message)
|
||||
old_chat_send_all(message)
|
||||
discord.send(message)
|
||||
end
|
||||
|
||||
minetest.register_on_chat_message(function(name, message)
|
||||
discord.send(('<%s> %s'):format(name, message))
|
||||
end)
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if dtime then
|
||||
timer = timer + dtime
|
||||
if timer > 0.2 then
|
||||
http.fetch({
|
||||
url = 'localhost:'..tostring(port),
|
||||
timeout = timeout,
|
||||
post_data = minetest.write_json({
|
||||
type = 'DISCORD-REQUEST-DATA'
|
||||
})
|
||||
}, discord.handle_response)
|
||||
timer = 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
discord.send('*** Server shutting down...')
|
||||
end)
|
||||
|
||||
discord.send('*** Server started!')
|
||||
|
16
relay.conf
16
relay.conf
@ -1,9 +1,9 @@
|
||||
[BOT]
|
||||
token = <Discord bot token goes here>
|
||||
command_prefix = !
|
||||
[RELAY]
|
||||
port = 8080
|
||||
channel_id = <Discord channel ID goes here>
|
||||
allow_logins = true
|
||||
clean_invites = true
|
||||
[BOT]
|
||||
token = <Discord bot token goes here>
|
||||
command_prefix = !
|
||||
[RELAY]
|
||||
port = 8080
|
||||
channel_id = <Discord channel ID goes here>
|
||||
allow_logins = true
|
||||
clean_invites = true
|
||||
use_nicknames = true
|
377
server.py
377
server.py
@ -1,189 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
from aiohttp import web
|
||||
import aiohttp
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
import configparser
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
config.read('relay.conf')
|
||||
|
||||
class Queue():
|
||||
def __init__(self):
|
||||
self.queue = []
|
||||
def add(self, item):
|
||||
self.queue.append(item)
|
||||
def get(self):
|
||||
if len(self.queue) >=1:
|
||||
item = self.queue[0]
|
||||
del self.queue[0]
|
||||
return item
|
||||
else:
|
||||
return None
|
||||
def get_all(self):
|
||||
items = self.queue
|
||||
self.queue = []
|
||||
return items
|
||||
def isEmpty(self):
|
||||
return len(self.queue) == 0
|
||||
|
||||
def clean_invites(string):
|
||||
return ' '.join([word for word in string.split() if not ('discord.gg' in word) and not ('discordapp.com/invite' in word)])
|
||||
|
||||
outgoing_msgs = Queue()
|
||||
command_queue = Queue()
|
||||
login_queue = Queue()
|
||||
|
||||
prefix = config['BOT']['command_prefix']
|
||||
|
||||
bot = commands.Bot(command_prefix=prefix, help_command=None)
|
||||
|
||||
channel_id = int(config['RELAY']['channel_id'])
|
||||
|
||||
connected = False
|
||||
|
||||
port = int(config['RELAY']['port'])
|
||||
token = config['BOT']['token']
|
||||
logins_allowed = True if config['RELAY']['allow_logins'] == 'true' else False
|
||||
do_clean_invites = True if config['RELAY']['clean_invites'] == 'true' else False
|
||||
do_use_nicknames = True if config['RELAY']['use_nicknames'] == 'true' else False
|
||||
|
||||
last_request = 0
|
||||
|
||||
channel = None
|
||||
authenticated_users = {}
|
||||
|
||||
def check_timeout():
|
||||
return time.time() - last_request <= 1
|
||||
|
||||
async def handle(request):
|
||||
global last_request
|
||||
last_request = time.time()
|
||||
text = await request.text()
|
||||
try:
|
||||
data = json.loads(text)
|
||||
if data['type'] == 'DISCORD-RELAY-MESSAGE':
|
||||
msg = discord.utils.escape_mentions(data['content'])[0:2000]
|
||||
if 'context' in data.keys():
|
||||
id = int(data['context'])
|
||||
user = bot.get_user(id)
|
||||
if user is not None:
|
||||
await user.send(msg)
|
||||
else:
|
||||
print('unyay')
|
||||
else:
|
||||
await channel.send(msg)
|
||||
return web.Response(text = 'Acknowledged') # discord.send should NOT block extensively on the Lua side
|
||||
if data['type'] == 'DISCORD_LOGIN_RESULT':
|
||||
user = bot.get_user(int(data['user_id']))
|
||||
if user is not None:
|
||||
if data['success'] is True:
|
||||
authenticated_users[int(data['user_id'])] = data['username']
|
||||
await user.send('Login successful.')
|
||||
else:
|
||||
await user.send('Login failed.')
|
||||
except:
|
||||
pass
|
||||
response = json.dumps({
|
||||
'messages' : outgoing_msgs.get_all(),
|
||||
'commands' : command_queue.get_all(),
|
||||
'logins' : login_queue.get_all()
|
||||
})
|
||||
return web.Response(text = response)
|
||||
|
||||
|
||||
app = web.Application()
|
||||
app.add_routes([web.get('/', handle),
|
||||
web.post('/', handle)])
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
global connected
|
||||
if not connected:
|
||||
connected = True
|
||||
global channel
|
||||
channel = await bot.fetch_channel(channel_id)
|
||||
|
||||
@bot.event
|
||||
async def on_message(message):
|
||||
global outgoing_msgs
|
||||
if check_timeout():
|
||||
if (message.channel.id == channel_id) and (message.author.id != bot.user.id):
|
||||
msg = {
|
||||
'author': message.author.name if not do_use_nicknames else message.author.display_name,
|
||||
'content': message.content.replace('\n', '/')
|
||||
}
|
||||
if do_clean_invites:
|
||||
msg['content'] = clean_invites(msg['content'])
|
||||
if msg['content'] != '':
|
||||
outgoing_msgs.add(msg)
|
||||
|
||||
await bot.process_commands(message)
|
||||
|
||||
@bot.command(help='Runs an ingame command from Discord.')
|
||||
async def cmd(ctx, command, *, args=''):
|
||||
if ((ctx.channel.id != channel_id) and ctx.guild is not None) or not logins_allowed:
|
||||
return
|
||||
if ctx.author.id not in authenticated_users.keys():
|
||||
await ctx.send('Not logged in.')
|
||||
return
|
||||
command = {
|
||||
'name': authenticated_users[ctx.author.id],
|
||||
'command': command,
|
||||
'params': args.replace('\n', '')
|
||||
}
|
||||
if ctx.guild is None:
|
||||
command['context'] = str(ctx.author.id)
|
||||
command_queue.add(command)
|
||||
|
||||
@bot.command(help='Logs into your ingame account from Discord so you can run commands. You should only run this command in DMs with the bot.')
|
||||
async def login(ctx, username, password=''):
|
||||
if not check_timeout() or not logins_allowed:
|
||||
return
|
||||
if ctx.guild is not None:
|
||||
await ctx.send(ctx.author.mention+' You\'ve quite possibly just leaked your password; it is advised that you change it at once.\n*This message will be automatically deleted*', delete_after = 10)
|
||||
return
|
||||
login_queue.add({
|
||||
'username' : username,
|
||||
'password' : password,
|
||||
'user_id' : str(ctx.author.id)
|
||||
})
|
||||
|
||||
@bot.command(help='Lists connected players and server information.')
|
||||
async def status(ctx, *, args=None):
|
||||
if not check_timeout():
|
||||
return
|
||||
if ((ctx.channel.id != channel_id) and ctx.guild is not None):
|
||||
return
|
||||
data = {
|
||||
'name': 'discord_relay',
|
||||
'command': 'status',
|
||||
'params': '',
|
||||
}
|
||||
if ctx.guild is None:
|
||||
data['context'] = str(ctx.author.id)
|
||||
command_queue.add(data)
|
||||
|
||||
async def runServer():
|
||||
runner = web.AppRunner(app)
|
||||
await runner.setup()
|
||||
site = web.TCPSite(runner, 'localhost', port)
|
||||
await site.start()
|
||||
|
||||
async def runBot():
|
||||
await bot.login(token)
|
||||
await bot.connect()
|
||||
|
||||
try:
|
||||
print('='*37+'\nStarting relay. Press Ctrl-C to exit.\n'+'='*37)
|
||||
loop = asyncio.get_event_loop()
|
||||
futures = asyncio.gather(runBot(), runServer())
|
||||
loop.run_until_complete(futures)
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
sys.exit()
|
||||
import sys
|
||||
from aiohttp import web
|
||||
import aiohttp
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
import configparser
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
config.read('relay.conf')
|
||||
|
||||
class Queue():
|
||||
def __init__(self):
|
||||
self.queue = []
|
||||
def add(self, item):
|
||||
self.queue.append(item)
|
||||
def get(self):
|
||||
if len(self.queue) >=1:
|
||||
item = self.queue[0]
|
||||
del self.queue[0]
|
||||
return item
|
||||
else:
|
||||
return None
|
||||
def get_all(self):
|
||||
items = self.queue
|
||||
self.queue = []
|
||||
return items
|
||||
def isEmpty(self):
|
||||
return len(self.queue) == 0
|
||||
|
||||
def clean_invites(string):
|
||||
return ' '.join([word for word in string.split() if not ('discord.gg' in word) and not ('discordapp.com/invite' in word)])
|
||||
|
||||
outgoing_msgs = Queue()
|
||||
command_queue = Queue()
|
||||
login_queue = Queue()
|
||||
|
||||
prefix = config['BOT']['command_prefix']
|
||||
|
||||
bot = commands.Bot(command_prefix=prefix, help_command=None)
|
||||
|
||||
channel_id = int(config['RELAY']['channel_id'])
|
||||
|
||||
connected = False
|
||||
|
||||
port = int(config['RELAY']['port'])
|
||||
token = config['BOT']['token']
|
||||
logins_allowed = True if config['RELAY']['allow_logins'] == 'true' else False
|
||||
do_clean_invites = True if config['RELAY']['clean_invites'] == 'true' else False
|
||||
do_use_nicknames = True if config['RELAY']['use_nicknames'] == 'true' else False
|
||||
|
||||
last_request = 0
|
||||
|
||||
channel = None
|
||||
authenticated_users = {}
|
||||
|
||||
def check_timeout():
|
||||
return time.time() - last_request <= 1
|
||||
|
||||
async def handle(request):
|
||||
global last_request
|
||||
last_request = time.time()
|
||||
text = await request.text()
|
||||
try:
|
||||
data = json.loads(text)
|
||||
if data['type'] == 'DISCORD-RELAY-MESSAGE':
|
||||
msg = discord.utils.escape_mentions(data['content'])[0:2000]
|
||||
if 'context' in data.keys():
|
||||
id = int(data['context'])
|
||||
user = bot.get_user(id)
|
||||
if user is not None:
|
||||
await user.send(msg)
|
||||
else:
|
||||
print('unyay')
|
||||
else:
|
||||
await channel.send(msg)
|
||||
return web.Response(text = 'Acknowledged') # discord.send should NOT block extensively on the Lua side
|
||||
if data['type'] == 'DISCORD_LOGIN_RESULT':
|
||||
user = bot.get_user(int(data['user_id']))
|
||||
if user is not None:
|
||||
if data['success'] is True:
|
||||
authenticated_users[int(data['user_id'])] = data['username']
|
||||
await user.send('Login successful.')
|
||||
else:
|
||||
await user.send('Login failed.')
|
||||
except:
|
||||
pass
|
||||
response = json.dumps({
|
||||
'messages' : outgoing_msgs.get_all(),
|
||||
'commands' : command_queue.get_all(),
|
||||
'logins' : login_queue.get_all()
|
||||
})
|
||||
return web.Response(text = response)
|
||||
|
||||
|
||||
app = web.Application()
|
||||
app.add_routes([web.get('/', handle),
|
||||
web.post('/', handle)])
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
global connected
|
||||
if not connected:
|
||||
connected = True
|
||||
global channel
|
||||
channel = await bot.fetch_channel(channel_id)
|
||||
|
||||
@bot.event
|
||||
async def on_message(message):
|
||||
global outgoing_msgs
|
||||
if check_timeout():
|
||||
if (message.channel.id == channel_id) and (message.author.id != bot.user.id):
|
||||
msg = {
|
||||
'author': message.author.name if not do_use_nicknames else message.author.display_name,
|
||||
'content': message.content.replace('\n', '/')
|
||||
}
|
||||
if do_clean_invites:
|
||||
msg['content'] = clean_invites(msg['content'])
|
||||
if msg['content'] != '':
|
||||
outgoing_msgs.add(msg)
|
||||
|
||||
await bot.process_commands(message)
|
||||
|
||||
@bot.command(help='Runs an ingame command from Discord.')
|
||||
async def cmd(ctx, command, *, args=''):
|
||||
if ((ctx.channel.id != channel_id) and ctx.guild is not None) or not logins_allowed:
|
||||
return
|
||||
if ctx.author.id not in authenticated_users.keys():
|
||||
await ctx.send('Not logged in.')
|
||||
return
|
||||
command = {
|
||||
'name': authenticated_users[ctx.author.id],
|
||||
'command': command,
|
||||
'params': args.replace('\n', '')
|
||||
}
|
||||
if ctx.guild is None:
|
||||
command['context'] = str(ctx.author.id)
|
||||
command_queue.add(command)
|
||||
|
||||
@bot.command(help='Logs into your ingame account from Discord so you can run commands. You should only run this command in DMs with the bot.')
|
||||
async def login(ctx, username, password=''):
|
||||
if not check_timeout() or not logins_allowed:
|
||||
return
|
||||
if ctx.guild is not None:
|
||||
await ctx.send(ctx.author.mention+' You\'ve quite possibly just leaked your password; it is advised that you change it at once.\n*This message will be automatically deleted*', delete_after = 10)
|
||||
return
|
||||
login_queue.add({
|
||||
'username' : username,
|
||||
'password' : password,
|
||||
'user_id' : str(ctx.author.id)
|
||||
})
|
||||
|
||||
@bot.command(help='Lists connected players and server information.')
|
||||
async def status(ctx, *, args=None):
|
||||
if not check_timeout():
|
||||
return
|
||||
if ((ctx.channel.id != channel_id) and ctx.guild is not None):
|
||||
return
|
||||
data = {
|
||||
'name': 'discord_relay',
|
||||
'command': 'status',
|
||||
'params': '',
|
||||
}
|
||||
if ctx.guild is None:
|
||||
data['context'] = str(ctx.author.id)
|
||||
command_queue.add(data)
|
||||
|
||||
async def runServer():
|
||||
runner = web.AppRunner(app)
|
||||
await runner.setup()
|
||||
site = web.TCPSite(runner, 'localhost', port)
|
||||
await site.start()
|
||||
|
||||
async def runBot():
|
||||
await bot.login(token)
|
||||
await bot.connect()
|
||||
|
||||
try:
|
||||
print('='*37+'\nStarting relay. Press Ctrl-C to exit.\n'+'='*37)
|
||||
loop = asyncio.get_event_loop()
|
||||
futures = asyncio.gather(runBot(), runServer())
|
||||
loop.run_until_complete(futures)
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
sys.exit()
|
||||
|
@ -1,2 +1,2 @@
|
||||
discord.port (Port to run the relay on.) int 8080
|
||||
discord.port (Port to run the relay on.) int 8080
|
||||
discord.text_color (Custom color for relayed messages.) string #ffffff
|
Loading…
x
Reference in New Issue
Block a user