whatup 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -0
- data/lib/whatup/cli/commands/interactive/dm.rb +46 -0
- data/lib/whatup/cli/commands/interactive/interactive.rb +23 -48
- data/lib/whatup/cli/thor_interactive.rb +32 -0
- data/lib/whatup/server/db_init.rb +8 -1
- data/lib/whatup/server/redirection.rb +3 -0
- data/lib/whatup/server/server.rb +49 -24
- data/lib/whatup/version.rb +1 -1
- data/lib/whatup.rb +6 -0
- metadata +4 -3
- data/lib/whatup/cli/commands/interactive/setup.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 974cf5162247e51601cda75af330d68aa1b9a77a73eb394228a5c4db17966445
|
4
|
+
data.tar.gz: 1a9113486f862c0ff3fc324458572f0e98055cd3459a126b84fc61ae44c90b77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9c93d48307ac342e04efa0b43a43c7d84d6208be74e87702b2f35c30eae0c01be4d6fca302ee6c691b2e6f4c41af6ea1d64d024f09d735cd503c35419744b1c
|
7
|
+
data.tar.gz: 1fcce685d6b140cb51452fdf299b0190212c42c036aa9821fc9f062ad8387c06d617f9068c52c37c8b877708ec072f01cc070ede433df061cfa161300da02370
|
data/.rubocop.yml
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
AllCops:
|
4
4
|
TargetRubyVersion: 2.4 # Modern Ruby
|
5
5
|
|
6
|
+
# !!defined?(RSpec)
|
7
|
+
Style/DoubleNegation:
|
8
|
+
Enabled: false
|
9
|
+
|
6
10
|
# attr_reader *%i[a b c]
|
7
11
|
Lint/UnneededSplatExpansion:
|
8
12
|
Enabled: false
|
@@ -17,6 +21,15 @@ Style/FrozenStringLiteralComment:
|
|
17
21
|
Exclude:
|
18
22
|
- 'spec/system_spec.rb'
|
19
23
|
|
24
|
+
# For long specs.
|
25
|
+
#
|
26
|
+
# describe 'some spec'
|
27
|
+
# ...
|
28
|
+
# end # describe 'some spec'
|
29
|
+
Style/CommentedKeyword:
|
30
|
+
Exclude:
|
31
|
+
- 'spec/system_spec.rb'
|
32
|
+
|
20
33
|
# The default is a bit restrictive
|
21
34
|
Metrics/AbcSize:
|
22
35
|
Max: 30
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'whatup/cli/thor_interactive'
|
5
|
+
|
6
|
+
module Whatup
|
7
|
+
module CLI
|
8
|
+
# Server commands
|
9
|
+
class Dm < Thor
|
10
|
+
extend ThorInteractive
|
11
|
+
|
12
|
+
Room = Whatup::Server::Room
|
13
|
+
Client = Whatup::Server::Client
|
14
|
+
|
15
|
+
desc 'msg [NAME]', 'Send a message to [NAME]'
|
16
|
+
def msg name
|
17
|
+
if recepient = Client.find_by(name: name)
|
18
|
+
say <<~MSG
|
19
|
+
Sending a direct message to #{name}...
|
20
|
+
|
21
|
+
The message can span multiple lines.
|
22
|
+
|
23
|
+
Type `.exit` when you're ready to send it.
|
24
|
+
MSG
|
25
|
+
current_user.composing_dm = recepient
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
say "That user doesn't exist!"
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'list', 'List your received messages'
|
33
|
+
def list
|
34
|
+
say 'Your direct messages:'
|
35
|
+
msgs = current_user.received_messages.map do |msg|
|
36
|
+
<<~MSG
|
37
|
+
From: #{msg.sender.name}
|
38
|
+
|
39
|
+
#{msg.content}
|
40
|
+
MSG
|
41
|
+
end.join('-' * 10)
|
42
|
+
say msgs
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,34 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'thor'
|
4
|
+
require 'whatup/cli/thor_interactive'
|
4
5
|
|
5
6
|
require 'whatup/client/client'
|
7
|
+
require 'whatup/cli/commands/interactive/dm'
|
6
8
|
|
7
9
|
module Whatup
|
8
10
|
module CLI
|
9
|
-
# Any methods of class `Whatup::CLI::Interactive` that rely on instance
|
10
|
-
# variables should be included here
|
11
|
-
COMMANDS = %i[
|
12
|
-
room
|
13
|
-
list
|
14
|
-
exit
|
15
|
-
dmlist
|
16
|
-
dm
|
17
|
-
].freeze
|
18
|
-
|
19
|
-
require 'whatup/cli/commands/interactive/setup'
|
20
|
-
|
21
11
|
# Interactive client commands that are available after connecting
|
22
12
|
#
|
23
13
|
# This class is run on the server
|
24
14
|
class Interactive < Thor
|
25
|
-
|
15
|
+
extend ThorInteractive
|
26
16
|
|
27
17
|
Room = Whatup::Server::Room
|
28
18
|
Client = Whatup::Server::Client
|
29
19
|
|
30
|
-
attr_accessor *%i[server current_user]
|
31
|
-
|
32
20
|
no_commands do
|
33
21
|
# Checks whether a given input string is a valid command
|
34
22
|
def self.command? msg
|
@@ -39,7 +27,7 @@ module Whatup
|
|
39
27
|
|
40
28
|
# Parses a client's input into a format suitable for Thor commands
|
41
29
|
#
|
42
|
-
#
|
30
|
+
# param [String] msg - the client's message
|
43
31
|
def self.parse_input msg
|
44
32
|
# Split user input at the first "option"
|
45
33
|
cmds, opts = msg&.split /-|--/, 2
|
@@ -48,8 +36,6 @@ module Whatup
|
|
48
36
|
cmds = cmds&.split(/\s+/)
|
49
37
|
opts = opts&.split(/\s+/)
|
50
38
|
|
51
|
-
# `Whatup::CLI::Interactive.new(cmds, opts)` expects arrays, and
|
52
|
-
# a final options hash
|
53
39
|
cmds = [] if cmds.nil?
|
54
40
|
opts = [] if opts.nil?
|
55
41
|
|
@@ -57,23 +43,17 @@ module Whatup
|
|
57
43
|
end
|
58
44
|
end
|
59
45
|
|
60
|
-
# Don't show app name in command help, i.e, instead of
|
61
|
-
# `app command desc`, use `command desc`
|
62
|
-
def self.banner task, _namespace = false, subcommand = false
|
63
|
-
task.formatted_usage(self, false, subcommand).to_s
|
64
|
-
end
|
65
|
-
|
66
46
|
desc 'list', 'Show all connected clients'
|
67
47
|
def list
|
68
48
|
say 'All connected clients:'
|
69
|
-
|
70
|
-
say "* #{
|
49
|
+
server.clients_except(current_user).each { |c| say " #{c.status}" }
|
50
|
+
say "* #{current_user.status}"
|
71
51
|
end
|
72
52
|
|
73
53
|
desc 'room [NAME]', 'Create and enter chatroom [NAME]'
|
74
54
|
def room name
|
75
55
|
if room = Room.find_by(name: name)
|
76
|
-
|
56
|
+
current_user.puts <<~MSG
|
77
57
|
Entering #{room.name}... enjoy your stay!
|
78
58
|
|
79
59
|
Type `.exit` to exit this chat room.
|
@@ -83,40 +63,27 @@ module Whatup
|
|
83
63
|
"- #{client.name}\n"
|
84
64
|
end.join}
|
85
65
|
MSG
|
86
|
-
|
66
|
+
current_user.update! room: room
|
87
67
|
|
88
|
-
room.broadcast except:
|
68
|
+
room.broadcast except: current_user do
|
89
69
|
<<~MSG
|
90
|
-
#{
|
70
|
+
#{current_user.name} has arrived! Play nice, kids.
|
91
71
|
MSG
|
92
72
|
end
|
93
73
|
|
94
|
-
room.clients <<
|
74
|
+
room.clients << current_user
|
95
75
|
return
|
96
76
|
end
|
97
77
|
|
98
|
-
room =
|
78
|
+
room = server.new_room! name: name, clients: [current_user]
|
99
79
|
|
100
|
-
|
80
|
+
current_user.puts <<~MSG
|
101
81
|
Created and entered #{room.name}... invite some people or something!
|
102
82
|
|
103
83
|
Type `.exit` to exit this chat room.
|
104
84
|
MSG
|
105
85
|
end
|
106
86
|
|
107
|
-
desc 'dmlist', 'List your received messages'
|
108
|
-
def dmlist
|
109
|
-
say 'Your direct messages:'
|
110
|
-
msgs = @current_user.received_messages.map do |msg|
|
111
|
-
<<~MSG
|
112
|
-
From: #{msg.sender.name}
|
113
|
-
|
114
|
-
#{msg.content}
|
115
|
-
MSG
|
116
|
-
end.join('-' * 10)
|
117
|
-
say msgs
|
118
|
-
end
|
119
|
-
|
120
87
|
desc 'dm [NAME]', 'Send a direct message to [NAME]'
|
121
88
|
def dm name
|
122
89
|
if recepient = Client.find_by(name: name)
|
@@ -127,7 +94,7 @@ module Whatup
|
|
127
94
|
|
128
95
|
Type `.exit` when you're ready to send it.
|
129
96
|
MSG
|
130
|
-
|
97
|
+
current_user.composing_dm = recepient
|
131
98
|
return
|
132
99
|
end
|
133
100
|
|
@@ -136,8 +103,16 @@ module Whatup
|
|
136
103
|
|
137
104
|
desc 'exit', 'Closes your connection with the server'
|
138
105
|
def exit
|
139
|
-
|
106
|
+
current_user.exit!
|
140
107
|
end
|
108
|
+
|
109
|
+
desc 'dm ...', 'Perform direct message commands'
|
110
|
+
long_desc <<~DESC
|
111
|
+
Perform direct message commands.
|
112
|
+
|
113
|
+
See `dm help [CMD] for more info about specific commands.
|
114
|
+
DESC
|
115
|
+
subcommand 'dm', Dm
|
141
116
|
end
|
142
117
|
end
|
143
118
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
# Allows us to use variables passed into a Thor class's `config[:locals]`
|
6
|
+
# Allows us to call the variables passed into `config[:locals]` as methods
|
7
|
+
# in our cli classes
|
8
|
+
module ThorInstanceVariableHook
|
9
|
+
def method_missing method, *args, &block
|
10
|
+
var = instance_variable_get(:@_initializer).last[:locals][method]
|
11
|
+
return var unless var.nil?
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond_to_missing? name, include_private = false
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module ThorInteractive
|
22
|
+
# Don't show app name in command help, i.e, instead of
|
23
|
+
# `app command desc`, use `command desc`
|
24
|
+
def banner task, _namespace = false, subcommand = false
|
25
|
+
task.formatted_usage(self, false, subcommand).to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
# Include the instance variable to method hook in our cli classes
|
29
|
+
def self.extended base
|
30
|
+
base.send :include, ThorInstanceVariableHook
|
31
|
+
end
|
32
|
+
end
|
@@ -9,6 +9,7 @@ module Whatup
|
|
9
9
|
extend Redirection
|
10
10
|
|
11
11
|
class << self
|
12
|
+
# Sets up our database, deleting all existing data.
|
12
13
|
def setup_db!
|
13
14
|
db = "#{Whatup.root}/db/whatup.db"
|
14
15
|
SQLite3::Database.new(db) unless File.exist?(db)
|
@@ -23,7 +24,13 @@ module Whatup
|
|
23
24
|
DROP TABLE IF EXISTS rooms;
|
24
25
|
SQL
|
25
26
|
|
26
|
-
|
27
|
+
if Whatup.testing?
|
28
|
+
# We silence output here, so that tests don't get cluttered
|
29
|
+
redirect(stdout: StringIO.new) { create_tables! }
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
create_tables!
|
27
34
|
end
|
28
35
|
|
29
36
|
private
|
@@ -4,6 +4,9 @@ module Whatup
|
|
4
4
|
module Server
|
5
5
|
module Redirection
|
6
6
|
# Reroutes stdin and stdout inside a block
|
7
|
+
#
|
8
|
+
# @param [IO#write] stdin - will redirect stdin to this
|
9
|
+
# @param [IO#write] stdout - will redirect stdout to this
|
7
10
|
def redirect stdin: $stdin, stdout: $stdout
|
8
11
|
original_stdin = $stdin
|
9
12
|
original_stdout = $stdout
|
data/lib/whatup/server/server.rb
CHANGED
@@ -26,6 +26,10 @@ module Whatup
|
|
26
26
|
|
27
27
|
attr_reader *%i[ip port address clients pid pid_file rooms]
|
28
28
|
|
29
|
+
# @param ip [String] The ip address to run the server on
|
30
|
+
# @param port [Integer] The port to run the server on
|
31
|
+
#
|
32
|
+
# @return [Whatup::Server::Server] The created server
|
29
33
|
def initialize ip: 'localhost', port:
|
30
34
|
@ip = ip
|
31
35
|
@port = port
|
@@ -53,26 +57,24 @@ module Whatup
|
|
53
57
|
|
54
58
|
# Listen for connections, then accept each in a separate thread
|
55
59
|
loop do
|
56
|
-
Thread.new(@socket.accept)
|
57
|
-
case handle_client client
|
58
|
-
when :exit
|
59
|
-
client.puts 'bye!'
|
60
|
-
Thread.kill Thread.current
|
61
|
-
end
|
62
|
-
end
|
60
|
+
Thread.new(@socket.accept) { |client| handle_client client }
|
63
61
|
end
|
64
62
|
rescue SignalException # In case of ^c
|
65
63
|
kill
|
66
64
|
end
|
67
65
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
# @param client [Whatup::Server::Client] The client to not retrieve
|
67
|
+
#
|
68
|
+
# @return [Array<Whatup::Server::Client>] All currently connected clients
|
69
|
+
# except for `client`
|
72
70
|
def clients_except client
|
73
71
|
@clients.reject { |c| c == client }
|
74
72
|
end
|
75
73
|
|
74
|
+
# @param clients [Array<Whatup::Server::Client>] Room's inital clients
|
75
|
+
# @param name [String] The room's name
|
76
|
+
#
|
77
|
+
# @return [Whatup::Server::Room] The created room
|
76
78
|
def new_room! clients: [], name:
|
77
79
|
room = Room.create! name: name, clients: clients
|
78
80
|
@rooms << room
|
@@ -83,6 +85,8 @@ module Whatup
|
|
83
85
|
|
84
86
|
# Receives a new client, then continuously gets input from that client
|
85
87
|
#
|
88
|
+
# @param client [Whatup::Server::Client] The client
|
89
|
+
#
|
86
90
|
# rubocop:disable Metrics/MethodLength
|
87
91
|
def handle_client client
|
88
92
|
client = create_new_client_if_not_existing! client
|
@@ -125,6 +129,10 @@ module Whatup
|
|
125
129
|
end
|
126
130
|
# rubocop:enable Metrics/MethodLength
|
127
131
|
|
132
|
+
# Handles inputing direct messages
|
133
|
+
#
|
134
|
+
# @param client [Whatup::Server::Client] `client` is the sender of
|
135
|
+
# the message, and `client.composing_dm` is the recipient.
|
128
136
|
def handle_dm client
|
129
137
|
msg = StringIO.new
|
130
138
|
loop do
|
@@ -144,6 +152,10 @@ module Whatup
|
|
144
152
|
client.composing_dm = nil
|
145
153
|
end
|
146
154
|
|
155
|
+
# Handles chatting.
|
156
|
+
#
|
157
|
+
# @param client [Whatup::Server::Client] The client. `client` is assumed
|
158
|
+
# to already belong to a room
|
147
159
|
def handle_chatting client
|
148
160
|
loop do
|
149
161
|
input = client.input!
|
@@ -166,6 +178,10 @@ module Whatup
|
|
166
178
|
# If no username is provided (i.e, blank), it assigns a random, anonymous
|
167
179
|
# username in the format `ANON-xxx`, where `xxx` is a random number upto
|
168
180
|
# 100, left-padded with zeros.
|
181
|
+
#
|
182
|
+
# @param client [TCPSocket] The client connection
|
183
|
+
#
|
184
|
+
# @return [Whatup::Server::Client] The created client
|
169
185
|
def create_new_client_if_not_existing! client
|
170
186
|
name = client.gets.chomp
|
171
187
|
rand_num = SecureRandom.random_number(100).to_s.rjust 3, '0'
|
@@ -194,22 +210,26 @@ module Whatup
|
|
194
210
|
client
|
195
211
|
end
|
196
212
|
|
213
|
+
# Initialize a new cli class using the initial command and options,
|
214
|
+
# and then set any instance variables, since Thor will create a new
|
215
|
+
# class instance when it's invoked.
|
216
|
+
#
|
217
|
+
# This achieve the same effect as
|
218
|
+
# `Whatup::CLI::Interactive.start(args)`, but allows us to set
|
219
|
+
# instance variables on the cli class.
|
220
|
+
#
|
221
|
+
# @param client [Whatup::Server::Client]
|
197
222
|
def run_thor_command! client:, msg:
|
198
|
-
# Initialize a new cli class using the initial command and options,
|
199
|
-
# and then set any instance variables, since Thor will create a new
|
200
|
-
# class instance when it's invoked.
|
201
223
|
cmds, opts = Whatup::CLI::Interactive.parse_input msg
|
202
|
-
Whatup::CLI::Interactive.new(
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
# instance variables on the cli class.
|
209
|
-
c.invoke c.args.first, c.args.drop(1)
|
210
|
-
end
|
224
|
+
cli = Whatup::CLI::Interactive.new(
|
225
|
+
cmds,
|
226
|
+
opts,
|
227
|
+
locals: {server: self, current_user: client} # config
|
228
|
+
)
|
229
|
+
cli.invoke cli.args.first, cli.args.drop(1)
|
211
230
|
end
|
212
231
|
|
232
|
+
# Kills the server if a PID for this app exists
|
213
233
|
def exit_if_pid_exists!
|
214
234
|
return unless running?
|
215
235
|
|
@@ -221,21 +241,26 @@ module Whatup
|
|
221
241
|
kill
|
222
242
|
end
|
223
243
|
|
244
|
+
# Connect a new socket for this server to start listening on the specified
|
245
|
+
# address and port.
|
224
246
|
def connect_to_socket!
|
225
|
-
@socket = TCPServer.open @port
|
247
|
+
@socket = TCPServer.open @ip, @port
|
226
248
|
rescue Errno::EADDRINUSE
|
227
249
|
puts 'Address already in use!'
|
228
250
|
kill
|
229
251
|
end
|
230
252
|
|
253
|
+
# Write this process's PID to the PID file
|
231
254
|
def write_pid!
|
232
255
|
File.open(@pid_file, 'w') { |f| f.puts Process.pid }
|
233
256
|
end
|
234
257
|
|
258
|
+
# @return [Bool] Whether or not a PID for this app exists
|
235
259
|
def running?
|
236
260
|
File.file? @pid_file
|
237
261
|
end
|
238
262
|
|
263
|
+
# Kills the server and removes the PID file
|
239
264
|
def kill
|
240
265
|
say "Killing the server with PID:#{Process.pid} ...", :red
|
241
266
|
FileUtils.rm_rf @pid_file
|
data/lib/whatup/version.rb
CHANGED
data/lib/whatup.rb
CHANGED
@@ -8,7 +8,13 @@ module Whatup
|
|
8
8
|
class Error < StandardError
|
9
9
|
end
|
10
10
|
|
11
|
+
# @return [String] The full path to application root
|
11
12
|
def self.root
|
12
13
|
Dir.pwd
|
13
14
|
end
|
15
|
+
|
16
|
+
# @return [Bool] Whether or not the app is running in a test environment
|
17
|
+
def self.testing?
|
18
|
+
!!defined?(RSpec)
|
19
|
+
end
|
14
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: whatup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Delk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -215,9 +215,10 @@ files:
|
|
215
215
|
- lib/whatup.rb
|
216
216
|
- lib/whatup/cli/cli.rb
|
217
217
|
- lib/whatup/cli/commands/client.rb
|
218
|
+
- lib/whatup/cli/commands/interactive/dm.rb
|
218
219
|
- lib/whatup/cli/commands/interactive/interactive.rb
|
219
|
-
- lib/whatup/cli/commands/interactive/setup.rb
|
220
220
|
- lib/whatup/cli/commands/server.rb
|
221
|
+
- lib/whatup/cli/thor_interactive.rb
|
221
222
|
- lib/whatup/client/client.rb
|
222
223
|
- lib/whatup/server/db_init.rb
|
223
224
|
- lib/whatup/server/models/application_record.rb
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Whatup
|
4
|
-
module CLI
|
5
|
-
# Implements a `before` hook to set the correct instance variables
|
6
|
-
# before any command methods.
|
7
|
-
#
|
8
|
-
# This is needed, since Thor creates another cli class instance when it is
|
9
|
-
# called with `invoke`, and we need to reassign any variables to the new
|
10
|
-
# cli instance.
|
11
|
-
#
|
12
|
-
# TODO: grab commands dynamically
|
13
|
-
module InteractiveSetup
|
14
|
-
Whatup::CLI::COMMANDS.each do |cmd|
|
15
|
-
define_method cmd do |*args|
|
16
|
-
cli = instance_variable_get(:@_initializer).last[:shell].base
|
17
|
-
@server = cli.server
|
18
|
-
@current_user = cli.current_user
|
19
|
-
super *args
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|