class SimpleTelnetServer::Connection
A basic Telnet server implemented with EventMachine.
Constants
- DEFAULT_OPTIONS
@return [Hash<Symbol, Object>] default values for (telnet) options
Attributes
custom handler of buffer content @return [Proc, call] will be passed the content of the buffer
Public Class Methods
Returns the Hash of registered commands. If they are not initialized yet (@commands), the one from superclass is used. If we’re TelnetServer itself, an empty Hash is used.
@return [Hash{String, Regexp => Symbol, Proc}]
# File lib/em-simple_telnet_server.rb, line 60 def commands @commands ||= if top_class? {} else superclass.commands.dup # copy from superclass end end
Registers an action for the command cmd (which can be a Regexp, === will be used). action can be a Symbol referring to an instance method or an instance of Proc. If action is not specified, the given block is used.
If cmd is a Regexp, all captures (MatchData#captures) will be passed to the block/method call (see {#run_command}).
@param cmd [String, Regexp] fixed command or regular expression that
matches a command and its arguments in capture groups
@param action [Symbol] the method to call. if given, the block passed is
ignored
# File lib/em-simple_telnet_server.rb, line 51 def has_command(cmd, action = nil, &blk) commands[cmd] = action || blk end
Sets the option opt to value. @param opt [Symbol] option key @param value [Object] anything
# File lib/em-simple_telnet_server.rb, line 25 def has_option(opt, value) options[opt] = value end
Returns the (telnet) options for this class. If they are not initialized yet, the ones from superclass (or SimpleTelnetServer
) are duplicated.
# File lib/em-simple_telnet_server.rb, line 31 def options @options ||= if top_class? DEFAULT_OPTIONS else superclass.options end.dup end
Starts the server on address addr and port port.
# File lib/em-simple_telnet_server.rb, line 18 def start_server(addr = 'localhost', port = options[:port]) EventMachine.start_server(addr, port, self) end
@return [Boolean] whether we’ve reached the top of the relevant
hieararchy
# File lib/em-simple_telnet_server.rb, line 70 def top_class? self == SimpleTelnetServer::Connection end
Public Instance Methods
@abstract Called automatically when a received command is not known (no matching entry in @commands) and sends back an error message.
@param command [String] the command that is not known
# File lib/em-simple_telnet_server.rb, line 136 def command_not_known(command) send_output "Command #{command.inspect} is not known." end
Returns the recognized commands for this telnet server.
# File lib/em-simple_telnet_server.rb, line 146 def commands self.class.commands end
@abstract If authentication is not required, there won’t be a login procedure and any peer is automatically logged in after connecting. @return [Boolean] whether this telnet server requires authentication
# File lib/em-simple_telnet_server.rb, line 106 def needs_authentication? false end
Returns the telnet options for this telnet server.
# File lib/em-simple_telnet_server.rb, line 141 def options self.class.options end
Called by EventMachine when a new connection attempt is made to this server (immediately after calling {#initialize}).
Checks if {#needs_authentication?}, which returns false
if not overridden. If it authentication is needed, it’ll initiate the login procedure (send login prompt, get username, get password, …).
Otherwise, any peer is authorized right away.
# File lib/em-simple_telnet_server.rb, line 93 def post_init @buffer = "" if needs_authentication? initiate_authentication else authorize # login anybody end end
Called by EventMachine when new data is received. Appends data to the buffer (@buffer). Calls {#process_buffer} if @buffer content ends with newline.
# File lib/em-simple_telnet_server.rb, line 113 def receive_data data # warn "Server: <<< #{data.inspect}" @buffer << data # work only with complete commands (ending with newline) process_buffer if @buffer.end_with? "\n" end
@abstract Called by EventMachine after the connection has been closed.
# File lib/em-simple_telnet_server.rb, line 128 def unbind end
Private Instance Methods
Invokes action along with the given arguments.
@param action [Proc, Symbol] code or a method on this server to call @param params [Array<Object>, nil] arguments for action (passed with splat
operator)
@raise [ArgumentError] if action is invalid
# File lib/em-simple_telnet_server.rb, line 258 def execute_action(action, args = nil) case action when Proc self.instance_exec(*args, &action) when Symbol self.send(action, *args) else raise ArgumentError, "invalid action #{action.inspect}" end end
Processes the content of @buffer.
If a {#custom_handler} is defined, it’s called with the current buffer contents. The handler will be removed, so if it has to stay, it has to re-add itself.
If the user is authorized, the commands in the buffer are executed.
If the user isn’t authorized, {#process_spam} is called, which does nothing by default.
Ensures that the buffer is cleared.
# File lib/em-simple_telnet_server.rb, line 179 def process_buffer if handler = custom_handler self.custom_handler = nil handler.(@buffer) elsif authorized? run_commands else process_spam end ensure @buffer.clear end
@abstract Called when data has been received while user isn’t authorized. This could be used to {#close_connection}.
# File lib/em-simple_telnet_server.rb, line 272 def process_spam end
Runs a command.
Stores command into @current_command for later use and looks it up. If it finds an action for it, executes the action.
If the matching command pattern is a Regexp, the captures are passed to the action.
@param command [String] command to run @raise [UnknownCommand] if the command is unknown
# File lib/em-simple_telnet_server.rb, line 241 def run_command(command) @current_command = command if pair = commands.find { |pattern,| pattern === command } pattern, action = pair args = $~.captures if pattern.is_a? Regexp execute_action(action, args) if action else raise UnknownCommand, command end end
Runs the commands in the buffer. Will call {#run_command} for each command (line), no matter if it is recognized or not. If {UnknownCommand} is raised, it’s handled using {#command_not_known}.
# File lib/em-simple_telnet_server.rb, line 223 def run_commands @buffer.lines.each do |command| run_command(command.chomp) end rescue UnknownCommand command_not_known $!.command end
Sends the command prompt.
# File lib/em-simple_telnet_server.rb, line 153 def send_command_prompt send_data options[:command_prompt] end
Sends output and then the command prompt. Appens new line to output first, if it doesn’t have one yet, unless it’s the empty string. @param output [String] output to send before command prompt
# File lib/em-simple_telnet_server.rb, line 161 def send_output(output) output += "\n" unless output.end_with? "\n" or output.empty? send_data output send_command_prompt end