lib/whatup/server/server.rb in whatup-0.2.4 vs lib/whatup/server/server.rb in whatup-0.2.5
- old
+ new
@@ -2,37 +2,44 @@
require 'socket'
require 'fileutils'
require 'securerandom'
+require 'sqlite3'
+require 'active_record'
require 'active_support/core_ext/object/blank'
-require 'whatup/server/client'
-require 'whatup/server/room'
+require 'whatup/server/db_init'
+require 'whatup/server/redirection'
+require 'whatup/server/models/client'
+require 'whatup/server/models/message'
+require 'whatup/server/models/room'
require 'whatup/cli/commands/interactive/interactive'
module Whatup
module Server
- class Server
+ class Server # rubocop:disable Metrics/ClassLength
include Thor::Shell
+ include DbInit
+ include Redirection
Client = Whatup::Server::Client
- # Used by the interactive client cli
- attr_reader *%i[ip port address clients max_id pid pid_file rooms]
+ attr_reader *%i[ip port address clients pid pid_file rooms]
- def initialize port:
- @ip = 'localhost'
+ def initialize ip: 'localhost', port:
+ @ip = ip
@port = port
@address = "#{@ip}:#{@port}"
@clients = []
@rooms = []
- @max_id = 1
@pid = Process.pid
@pid_file = "#{Dir.home}/.whatup.pid"
+
+ DbInit.setup_db!
end
# Starts the server.
#
# The server continuously loops, and handle each new client in a separate
@@ -60,74 +67,93 @@
def find_client_by name:
@clients.select { |c| c.name == name }&.first
end
+ def clients_except client
+ @clients.reject { |c| c == client }
+ end
+
def new_room! clients: [], name:
- room = Room.new name: name, clients: clients
+ room = Room.create! name: name, clients: clients
@rooms << room
room
end
private
# Receives a new client, then continuously gets input from that client
#
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
+ # rubocop:disable Metrics/MethodLength
def handle_client client
client = create_new_client_if_not_existing! client
# Loop forever to maintain the connection
loop do
- handle_chatting(client) if client.chatting?
+ @clients.reject! &:deleted
+ Thread.current.exit if client.deleted
+
+ if client.composing_dm?
+ handle_dm client
+ elsif client.chatting?
+ handle_chatting client
+ end
+
# Wait until we get a valid command. This takes as long as the client
# takes.
msg = client.input! unless Whatup::CLI::Interactive.command?(msg)
puts "#{client.name}> #{msg}"
- # Initialize a new cli class using the initial command and options,
- # and then set any instance variables, since Thor will create a new
- # class instance when it's invoked.
- cmds, opts = Whatup::CLI::Interactive.parse_input msg
- cli = Whatup::CLI::Interactive.new(cmds, opts).tap do |c|
- c.server = self
- c.current_user = client
- end
-
begin
# Send the output to the client
redirect stdin: client.socket, stdout: client.socket do
# Invoke the cli using the provided commands and options.
-
- # This _should_ achieve the same effect as
- # `Whatup::CLI::Interactive.start(args)`, but allows us to set
- # instance variables on the cli class.
- cli.invoke cli.args.first, cli.args[1..cli.args.size - 1]
+ run_thor_command! client: client, msg: msg
end
rescue RuntimeError,
Thor::InvocationError,
Thor::UndefinedCommandError => e
puts e.message
client.puts 'Invalid input or unknown command'
rescue ArgumentError => e
puts e.message
client.puts e.message
end
- msg = nil # rubocop:disable Lint/UselessAssignment
+ msg = nil
end
end
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
+ # rubocop:enable Metrics/MethodLength
+ def handle_dm client
+ msg = StringIO.new
+ loop do
+ input = client.input!
+ puts "#{client.name}> #{input}"
+ if input == '.exit'
+ client.puts "Finished dm to `#{client.composing_dm.name}`."
+ break
+ end
+ msg.puts input
+ end
+ client.composing_dm
+ .received_messages << Message.new(
+ sender: client,
+ content: msg.string
+ )
+ client.composing_dm = nil
+ end
+
def handle_chatting client
loop do
input = client.input!
room = client.room
puts "#{client.name}> #{input}"
if input == '.exit'
client.leave_room!
+ client.puts "Exited `#{room.name}`."
break
end
room.broadcast except: client do
"#{client.name}> #{input}"
end
@@ -145,38 +171,44 @@
rand_num = SecureRandom.random_number(100).to_s.rjust 3, '0'
name = name == '' ? "ANON-#{rand_num}" : name
if @clients.any? { |c| c.name == name }
client.puts 'That name is taken! Goodbye.'
- client.exit!
+ client.puts 'END'
+ client.close
+ Thread.current.exit
end
- @clients << client = Client.new(
- id: new_client_id,
+ @clients << client = Client.create!(
name: name,
socket: client
)
puts "#{client.name} just showed up!"
- client.puts "Hello, #{client.name}!"
+ client.puts <<~MSG
+ Hello, #{client.name}!
+
+ Welcome to whatup.
+
+ To get started, type `help`.
+ MSG
client
end
- # @return A new, unique client identification number
- def new_client_id
- @max_id += 1
- end
+ def run_thor_command! client:, msg:
+ # Initialize a new cli class using the initial command and options,
+ # and then set any instance variables, since Thor will create a new
+ # class instance when it's invoked.
+ cmds, opts = Whatup::CLI::Interactive.parse_input msg
+ Whatup::CLI::Interactive.new(cmds, opts).tap do |c|
+ c.server = self
+ c.current_user = client
- # Reroutes stdin and stdout inside a block
- def redirect stdin: $stdin, stdout: $stdout
- original_stdin = $stdin
- original_stdout = $stdout
- $stdin = stdin
- $stdout = stdout
- yield
- ensure
- $stdin = original_stdin
- $stdout = original_stdout
+ # This _should_ achieve the same effect as
+ # `Whatup::CLI::Interactive.start(args)`, but allows us to set
+ # instance variables on the cli class.
+ c.invoke c.args.first, c.args.drop(1)
+ end
end
def exit_if_pid_exists!
return unless running?