whatup 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|