vrobot4/source/server.rb

260 lines
8.1 KiB
Ruby

# Module for vrobot4 server interfaces.
module Vrobot4::Server
class Mod_Base < Vrobot4::Module::Module
def initialize info
super
register :c_help, "help", "Prints documentation for commands."
register :c_die, "die", "Kills all bot instances.", roles: "o"
register :c_modr, "modr", "Reloads a module.", roles: "o"
register :c_modl, "modl", "Loads a module.", roles: "o"
register :c_modu, "modu", "Unloads a module.", roles: "o"
register :c_dbg, "dbg", "Sets the debug level.", roles: "o"
end
# @!visibility private
def c_help m, argv
if argv.empty?
cmds = []
m.serv.each_mod {|mod| cmds << mod.cmds(m).keys.join(", ")}
cmds.delete ""
m.reply "Commands:", cmds.join(", ")
else
m.serv.each_mod do |mod|
if (cmd = mod.cmds(m)[argv])
return m.reply argv + ":", cmd.help_str
end
end
m.reply "Command not found:", argv
end
end
# @!visibility private
def c_die m, argv
m.serv.voice_quit m if m.serv.flags.include? "A"
m.reply \
["STATUS: DYING",
"ded",
"proceeding to die",
"bye",
"dedededed",
"Thanks, bye!",
"GOTTAGOBYE",
"the orks insisted upon dying"].sample
exit
end
# @!visibility private
def c_modr m, argv
argv = check_args argv.split, "S", "S"
m.serv.drop_mod argv[0]
load argv[1], true if argv.length > 1
m.serv.load_mod argv[0]
end
# @!visibility private
def c_modl m, argv
m.serv.load_mod argv
end
# @!visibility private
def c_modu m, argv
m.serv.drop_mod argv
end
# @!visibility private
def c_dbg m, argv
check_args argv, "N"
Vrobot4.debug = argv.to_i
end
# @!visibility private
def on_command m, cnam, argv
Vrobot4.log :DEBUGV, "command", cnam.to_s, argv
super
end
end
private_constant :Mod_Base
# Generic user information. May be extended.
class User
attr_reader :name # @return [String] plaintext name of the user
attr_reader :roles # @return [String] list of user's roles
end
# Generic channel information. May be extended.
class Channel
attr_reader :name # @return [String] plaintext name of the channel
end
# Generic event information. May not be extended.
class Message
attr_reader :msg # @return [String] plaintext of message
attr_reader :user # @return [User] user that triggered this message
attr_reader :chan # @return [Channel] channel this message was sent to
attr_reader :serv # @return [Server] server this message was sent to
# @param info [Hash] A hash containing message info. Keys may be omitted.
# [:msg] Plaintext of message.
# [:user] User that triggered this message.
# [:chan] Channel that this message was sent to.
# [:serv] Server this message was sent to.
# [:reply] Method that sends a message to the specified channel.
# [:reply_b] Method that sends a large message to the specified channel.
def initialize(**info)
@msg = info[:msg]
@user = info[:user]
@chan = info[:chan]
@serv = info[:serv]
@reply = info[:reply]
@reply_b = info[:reply_b]
end
# Sends a message to the channel this message originated from.
def reply *args
@reply.call args.join(" ")
end
# Sends a large message to the channel this message originated from.
def reply_b *args
@reply_b.call args.join(" ")
end
end
# Generic server interface.
class Server
attr_reader :mprm # @return [Hash] module permissions for this server
# @param info [Hash] arbitrary extra information for this server
def initialize info
@info = info
@modules = [Mod_Base.new(nil)]
load_permissions info["permissions"]
end
# Loads and initializes a module into the load list.
def load_mod mod
mt = Vrobot4::Module.get_module_type(mod)
if mt[:server] and mt[:server] != self.class.type or
mt[:servflags] and mt[:servflags] !~ flags
raise ArgumentError, "Module " + mod + " not valid for this server"
end
@modules << mt[:type].new(@info[mod])
end
# Drops a module from the load list.
def drop_mod mod
mt = Vrobot4::Module.get_module_type(mod)
@modules.each_index do |i|
@modules.delete_at i if @modules[i].is_a? mt[:type]
end
end
# Yields for every module loaded in the server.
def each_mod
@modules.each {|mod| yield mod}
end
# (see Vrobot4::Module::Module#on_message)
# Passes information to all modules.
def on_message m
@modules.each {|mod| break if mod.on_message m}
end
# (see Vrobot4::Module::Module#on_command)
# Passes information to all modules.
def on_command m, cnam, argv
@modules.each {|mod| break if mod.on_command m, cnam, argv}
end
# Connect to the server.
def connect
raise NotImplementedError, "Server#connect not implemented"
end
# Flags for this server.
# [A] Server has audio capabilities and inherits from AudioServer.
# [L] Server cannot support large text dumps
# (code should assume <=4 lines, 240 characters per as maximum)
# @return [String]
def flags
""
end
# Basic command message handler.
#
# Checks if the message starts with "." and splits the command
# from the arguments, then emits an on_command event.
#
# Otherwise, it will emit an on_message event.
#
# @param m [Vrobot4::Server::Message] the message to parse and emit
def handle_text_cmd m
if m.msg.start_with? '.'
arg = m.msg.split(' ', 2)
on_command m, arg[0][1 .. -1], (arg[1] or "")
else
on_message m
end
end
protected
# Implementation defined permission loader.
# Loads information into +@mprm+.
def load_permissions pinf
raise NotImplementedError, "Server#load_permissions not implemented"
end
end
# Basis for an audio-enabled server interface.
class AudioServer < Server
# Joins a voice channel, using a message for context.
# @param m [Vrobot4::Server::Message] message for context
def voice_join m
raise NotImplementedError, "AudioServer#voice_join not implemented"
end
# Quits a voice channel, using a message for context.
# @param m [Vrobot4::Server::Message] message for context
def voice_quit m
raise NotImplementedError, "AudioServer#voice_quit not implemented"
end
# Plays an arbitrary audio file in a given context.
# @param m [Vrobot4::Server::Message] message for context
# @param io [IO] audio stream to play
def voice_play m, io
raise NotImplementedError, "AudioServer#voice_play not implemented"
end
# Check if the bot is playing audio in a given context.
# @param m [Vrobot4::Server::Message] message for context
def is_playing? m
raise NotImplementedError, "AudioServer#is_playing? not implemented"
end
# (see Vrobot4::Server::Server#flags)
def flags
"A"
end
end
# Adds a server type to the global list.
# @param type [Class] server type to add
def self.add_server_type type
@@server_types[type.type] = type
Vrobot4.log :INFO, "added server type:", type.type
end
# Gets a server type by name from the global list.
# @param name [String] name of the server type to find
# @return [Vrobot4::Server::Server] the server type
def self.get_server_type name
@@server_types[name]
end
private
@@server_types = {}
end
## EOF