# Discord backend. module Backend_Discord require 'discordrb' # Helper for channel permissions handling. class ChannelPerms def initialize() @cprm = {} end # @param chan [Bot_Discord::Channel] the channel for this permission # @return [Boolean] true if the channel is enabled, false otherwise. def [](chan) @cprm[chan.name] or @cprm[chan.real.id] end # Sets a channel's permission on/off. # @param chan [Bot_Discord::Channel] the channel for this permission # @param set [Boolean] if this permission should be set # @return [void] def []=(chan, set) @cprm[chan] = set end end # A Discord user. class User < Vrobot4::Server::User attr_reader :real # @return [Discordrb::User] the instance # @param user [Discordrb::User] the discord user # @param ops [Array] list of operator role IDs # @param hop [Array] list of half-operator role IDs def initialize user, ops, hop @real = user @name = user.name @id = user.id @roles = "v" if user.is_a? Discordrb::Member if user.owner? @roles += "Ooh" elsif ops and ops.any? do |role| user.role? role end @roles += "oh" elsif hop and hop.any? do |role| user.role? role end @roles += "h" end end end end # A Discord channel. class Channel < Vrobot4::Server::Channel attr_reader :real # @return [Discordrb::Channel] the instance # @param chan [Discordrb::Channel] the discord channel def initialize chan @real = chan @name = ?# + chan.name @id = chan.id end end # A Discord server. class Server < Vrobot4::Server::AudioServer # The server type name. def self.type() "Discord" end attr_reader :real # @return [Discordrb::Server] the instance # (see Vrobot4::Server::Server#initialize) # @param real [Discordrb::Server] the instance def initialize info, bot, real super info, bot @real = real @id = real.id @ops = info[:admins] || [] @hop = info[:halfop] || [] if mods = info[:modules] for mod in mods load_mod mod end end end # (see Vrobot4::Server::AudioServer#voice_quit) def voice_quit m @bot.real.voice_destroy m.chan.real.server.id end # (see Vrobot4::Server::AudioServer#voice_play) def voice_play m, fname vc = @bot.real.voice m.chan.real raise RuntimeError, "I'm not in a voice channel" unless vc vc.play_file fname end # (see Vrobot4::Server::AudioServer#voice_play_io) def voice_play_io m, io vc = @bot.real.voice m.chan.real raise ArgumentError, "Invalid IO stream" unless io raise RuntimeError, "I'm not in a voice channel" unless vc Thread.new do vc.play_io io end # HACK sleep 1 oldst = nil while vc.stream_time != oldst oldst = vc.stream_time sleep 5 end end # (see Vrobot4::Server::Server#flags) def flags ?A end protected # (see Vrobot4::Server::Server#load_permissions) def load_permissions pinf @mprm = {chan: {}, role: {}, glob: {}} return unless pinf pinf.each do |pr| mod = Vrobot4::Module.get_module_type(pr[:module])[:type] if pr.key? :channel @mprm[:chan][mod] = ChannelPerms.new unless @mprm[:chan][mod] @mprm[:chan][mod][pr[:channel]] = true elsif pr.key? :roles @mprm[:role][mod] = pr[:roles] elsif pr.key? :enable @mprm[:glob][mod] = pr[:enable] end end end end # A bot implementation for Discord using discordrb. class Bot < Vrobot4::Robots::Bot # The bot type name. def self.type() "Discord" end Vrobot4::Robots.add_bot_type self attr_reader :real def initialize info super @servers = {} @real = Discordrb::Bot.new \ token: info[:apikey], client_id: info[:client] @real.ready do |evt| for _, serv in evt.bot.servers add_server serv end end @real.message do |evt| if evt.server serv = get_server evt.server m = Vrobot4::Server::Message.new \ msg: evt.message.content, user: User.new(evt.user, @ops, @hop), chan: Channel.new(evt.channel), serv: serv, bot: self, reply: -> (text) {evt.channel.send text}, reply_b: -> (text) {evt.channel.send "```\n#{text}```"} serv.handle_text_cmd m end end end # (see Vrobot4::Robots::Bot#connect) def connect @real.run end protected # Adds a server to the hash. # @param serv [Discordrb::Server] server instance # @return [Server] def add_server serv Vrobot4.log :DEBUG, "initializing server #{serv.id}" @servers[serv.id] = Server.new @info[serv.id] || {}, self, serv end # Finds a server in the hash, potentially adding it. # @param serv [Discordrb::Server] server instance # @return [Server] def get_server serv @servers[serv.id] || add_server(serv) end end end ## EOF