meshchat 0.11.2 → 0.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 769222556d02960c10f6e09f5216979a9d3b99b0
4
- data.tar.gz: d2fb3690c939227b155933e7f404cea22b4a8ab4
3
+ metadata.gz: 677204be2321055039fb7d40db56bf98240b65c5
4
+ data.tar.gz: 7183a0315be9faa2f4730c3a6f3c5d718ae184b6
5
5
  SHA512:
6
- metadata.gz: 5cf9b9d8a513a1a1e92e8e8b7afb1ada009dad234a3a935cc846b7bab8f34ced4539dbf643444b3c393ac6e9d5ee4309ea81b90b3da58956037dde9d355e6d2f
7
- data.tar.gz: 273717543e8ec2081d2d2e7545da2fcea27eb398e7297eceb3f8a4a8976a86ce7f9f8c82d59772af1b4a42ff802de2af4caa476e90c0af0d2d7cb7122ea3d819
6
+ metadata.gz: cdf0dfc6e780ce78e04f0986ea82c895e3ced5a76ef0e69184e655aa5d2e3d411a5a53505fdc5f127d3e1820c75f053f15c72fd928eb8f6c23badc5fb1da3853
7
+ data.tar.gz: 78e642349854b82423d953819e49f326046b5096f3c876611acdc12e1e5584cd98ae1c62d886f044867bf8176f4d247d88621dc009ed2467a54683ad9cdcdd1a
@@ -31,6 +31,8 @@ module Meshchat
31
31
 
32
32
  table.column :on_local_network, :boolean, default: true, null: false
33
33
  table.column :on_relay, :boolean, default: false, null: false
34
+
35
+ table.timestamps
34
36
  end
35
37
  end
36
38
  end
@@ -12,3 +12,4 @@ identity:
12
12
  current_alias: 'Your current name/alias is: %{name}'
13
13
  node:
14
14
  not_found: "Node not found, or does not have a location. Have you imported %{name}?"
15
+ multiple_with_alias: "!! You know multiple people named '%{name}', which would you like to send to?"
@@ -22,6 +22,10 @@ module Meshchat
22
22
 
23
23
  @_to = to
24
24
  end
25
+
26
+ def display
27
+ super.merge(to: _to)
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -7,6 +7,7 @@ module Meshchat
7
7
  COMMAND = '/'
8
8
 
9
9
  attr_accessor :_message_dispatcher, :_message_factory, :_cli
10
+ attr_accessor :_whisper_lock_target
10
11
 
11
12
  def initialize(message_dispatcher, message_factory, cli)
12
13
  self._message_dispatcher = message_dispatcher
@@ -32,6 +33,14 @@ module Meshchat
32
33
  klass.new(input, _message_dispatcher, _message_factory, self)
33
34
  end
34
35
 
36
+ def clear_whisper_lock
37
+ self._whisper_lock_target = nil
38
+ end
39
+
40
+ def whisper_lock_to(node)
41
+ self._whisper_lock_target = node
42
+ end
43
+
35
44
  def create_for_input(input)
36
45
  klass =
37
46
  if is_command?(input)
@@ -39,11 +48,20 @@ module Meshchat
39
48
  elsif is_whisper?(input)
40
49
  Command::Whisper
41
50
  else
51
+ return whisper_for_locked_target(input) if _whisper_lock_target
42
52
  Command::Chat
43
53
  end
44
54
 
45
55
  create_with_class(input, klass)
46
56
  end
57
+
58
+ def whisper_for_locked_target(input)
59
+ command = Command::Whisper.new(
60
+ input, _message_dispatcher, _message_factory, self)
61
+
62
+ command._target_node = _whisper_lock_target
63
+ command
64
+ end
47
65
  end
48
66
  end
49
67
  end
@@ -16,7 +16,18 @@ module Meshchat
16
16
 
17
17
  def initialize
18
18
  Readline.callback_handler_install('> ') do |line|
19
- EventMachine.next_tick { @input_receiver.create_input(line) }
19
+ EventMachine.next_tick { handle_input(line) }
20
+ end
21
+ end
22
+
23
+ def handle_input(line)
24
+ if @callback
25
+ # call and clear, so we can resume normal
26
+ # input handling
27
+ @callback.call(line)
28
+ @callback = nil
29
+ else
30
+ @input_receiver.create_input(line)
20
31
  end
21
32
  end
22
33
 
@@ -32,6 +43,10 @@ module Meshchat
32
43
  @input_receiver = receiver
33
44
  end
34
45
 
46
+ def callback_on_next_tick=(callback)
47
+ @callback = callback
48
+ end
49
+
35
50
  end
36
51
 
37
52
  class << self
@@ -40,6 +55,14 @@ module Meshchat
40
55
  aliases = Meshchat::Node.all.map { |n| "#{n.alias_name}" }
41
56
  commands + aliases
42
57
  end
58
+
59
+ def input_handler
60
+ @input_handler
61
+ end
62
+
63
+ def input_handler=(handler)
64
+ @input_handler = handler
65
+ end
43
66
  end
44
67
 
45
68
  def start
@@ -48,12 +71,13 @@ module Meshchat
48
71
  conn = EventMachine.watch $stdin, Handler
49
72
  conn.notify_readable = true
50
73
  conn.input_receiver = _input_receiver
51
-
74
+ self.class.input_handler = conn
52
75
  # update auto completion
53
76
  completion = proc { |s| self.class.autocompletes.grep(/^#{Regexp.escape(s)}/) }
54
77
  Readline.completion_proc = completion
55
78
  end
56
79
 
80
+
57
81
  # def initialize(*args)
58
82
  # super(args)
59
83
  #
@@ -7,13 +7,17 @@ module Meshchat
7
7
  eager_autoload do
8
8
  autoload :Base
9
9
  autoload :Chat
10
+ autoload :Emote
11
+ autoload :Whisper
12
+ autoload :WhisperLock
13
+ autoload :AllChatLock
14
+
10
15
  autoload :Identity
11
16
  autoload :Irb
12
17
  autoload :Config
13
18
  autoload :Ping
14
19
  autoload :PingAll
15
20
  autoload :Server
16
- autoload :Whisper
17
21
  autoload :Exit
18
22
  autoload :SendDisconnect
19
23
  autoload :Help
@@ -22,8 +26,10 @@ module Meshchat
22
26
  autoload :Offline
23
27
  autoload :Share
24
28
  autoload :Import
25
- autoload :Emote
26
29
  autoload :Roll
30
+
31
+ # Utility
32
+ autoload :NodeFinder
27
33
  end
28
34
 
29
35
  COMMAND_MAP = {
@@ -46,7 +52,9 @@ module Meshchat
46
52
  Base::SEND_DISCONNECT => SendDisconnect,
47
53
  Base::EMOTE => Emote,
48
54
  Base::ROLL => Roll,
49
- Base::CHAT => Chat
55
+ Base::CHAT => Chat,
56
+ Base::WHISPER_LOCK => WhisperLock,
57
+ Base::ALL_CHAT_LOCK => AllChatLock
50
58
  }.freeze
51
59
  end
52
60
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ module Meshchat
3
+ module Ui
4
+ module Command
5
+ class AllChatLock < Command::Base
6
+ def self.description
7
+ 'sets the current chat to the "All Chat"'
8
+ end
9
+
10
+ def handle
11
+ return unless _input_factory._whisper_lock_target
12
+ Display.info 'whisper lock disabled'
13
+ _input_factory.clear_whisper_lock
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -30,6 +30,8 @@ module Meshchat
30
30
  SEND_DISCONNECT = 'senddisconnect'
31
31
  EMOTE = 'me'
32
32
  ROLL = 'roll'
33
+ WHISPER_LOCK = 'wl'
34
+ ALL_CHAT_LOCK = 'all'
33
35
 
34
36
  attr_reader :_input, :_message_dispatcher
35
37
  attr_reader :_message_factory, :_input_factory
@@ -47,7 +49,7 @@ module Meshchat
47
49
  if klass
48
50
  _input_factory.create(for_input: _input, with_class: klass).handle
49
51
  else
50
- Display.alert 'not implemented...'
52
+ Display.alert "#{command} not implemented..."
51
53
  end
52
54
  end
53
55
 
@@ -0,0 +1,58 @@
1
+ module Meshchat
2
+ module Ui
3
+ module Command
4
+ module NodeFinder
5
+ module_function
6
+
7
+ def find_by_target(string, &block)
8
+ search_key = string.start_with?('#') ? :uid : :alias_name
9
+ nodes = Node.where(search_key => string)
10
+ if nodes.length == 0
11
+ return Display.warning('No node by: ' + string)
12
+ end
13
+
14
+ return block.call(nodes.first) if nodes.length == 1
15
+
16
+ Display.warning I18n.t('node.multiple_with_alias', name: string)
17
+ ask_for_specification(nodes, block)
18
+ end
19
+
20
+ def ask_for_specification(nodes, block)
21
+ # there are now more than 1 nodes
22
+ display_nodes(nodes)
23
+
24
+
25
+ # insert a callback into the input handler to run the next
26
+ # time a line is received
27
+ #
28
+ # TODO: this feels gross, is there a better way?
29
+ # TODO: move this callback from ReadlineInput to the Input Base
30
+ CLI::ReadlineInput.input_handler.callback_on_next_tick = lambda do |line|
31
+ answer = line.to_i
32
+ node = nodes[answer]
33
+ # finally, send the mesasge
34
+ # (or do whatever this is)
35
+ # but usually, it sending the message
36
+ block.call(node)
37
+ end
38
+ end
39
+
40
+ def display_nodes(nodes)
41
+ # write header
42
+ Display.info "\t\t UID Last Seen"
43
+ Display.info '-' * 60
44
+
45
+ # write nodes
46
+ nodes.each_with_index do |node, index|
47
+ i = index.to_s
48
+ alias_name = node.alias_name
49
+ uid = node.uid[0..5]
50
+ last_seen = node.updated_at&.strftime('%B %e, %Y %H:%M:%S') || 'never'
51
+ line = "%-2s | %-15s %-8s %s" % [i, alias_name, uid, last_seen]
52
+ Display.info line
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -3,35 +3,48 @@ module Meshchat
3
3
  module Ui
4
4
  module Command
5
5
  class Whisper < Command::Base
6
+ attr_accessor :_target_node
7
+
6
8
  def self.description
7
9
  'sends a private message to a spepcific person'
8
10
  end
9
11
 
10
12
  def target
11
13
  # get first arg
14
+ return _target_node.alias_name if _target_node
12
15
  command
13
16
  end
14
17
 
15
18
  def message
19
+ return _input if _target_node
16
20
  command_args[1..command_args.length].try(:join, ' ')
17
21
  end
18
22
 
19
23
  def handle
20
- node = Node.find_by_alias_name(target)
24
+ return send_message_to_node(_target_node) if _target_node
25
+ find_node_and_whisper(target)
26
+ end
21
27
 
22
- if node
23
- m = _message_factory.create(
24
- Network::Message::WHISPER,
25
- data: {
26
- message: message,
27
- to: target
28
- })
28
+ def send_message_to_node(node)
29
+ m = _message_factory.create(
30
+ Network::Message::WHISPER,
31
+ data: {
32
+ message: message,
33
+ to: target
34
+ })
29
35
 
30
- Display.whisper m.display
36
+ Display.whisper m.display
37
+
38
+ _message_dispatcher.send_message(node: node, message: m)
39
+ end
31
40
 
32
- _message_dispatcher.send_message(node: node, message: m)
33
- else
34
- Display.alert "node for #{target} not found or is not online"
41
+ def find_node_and_whisper(target)
42
+ NodeFinder.find_by_target(target) do |node|
43
+ if node
44
+ send_message_to_node(node)
45
+ else
46
+ Display.alert "node for #{target} not found or is not online"
47
+ end
35
48
  end
36
49
  end
37
50
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module Meshchat
3
+ module Ui
4
+ module Command
5
+ class WhisperLock < Command::Base
6
+ def self.description
7
+ 'sets the current chat to to a chosen person'
8
+ end
9
+
10
+ def target
11
+ # get first arg
12
+ command_args[1]
13
+ end
14
+
15
+ def handle
16
+ NodeFinder.find_by_target(target) do |node|
17
+ Display.info "whisper-locked to #{node.alias_name}##{node.uid}"
18
+ _input_factory.whisper_lock_to(node)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -35,7 +35,7 @@ module Meshchat
35
35
 
36
36
  def info(msg)
37
37
  if msg.is_a?(Hash)
38
- message_parts_for(msg) do |time, name, message|
38
+ message_parts_for(msg) do |time, name, message, _|
39
39
  colored_time = (time.to_s + ' ').colorize(:magenta)
40
40
  colored_name = (name + ' ').colorize(:light_black)
41
41
  colored_message = message.colorize(:light_black)
@@ -60,7 +60,7 @@ module Meshchat
60
60
  end
61
61
 
62
62
  def emote(msg)
63
- message_parts_for(msg) do |time, name, message|
63
+ message_parts_for(msg) do |time, name, message, _|
64
64
  colored_time = (time.to_s + ' ').colorize(:magenta)
65
65
  colored_name = (name + ' ').colorize(:light_black)
66
66
  colored_message = message.colorize(:light_black)
@@ -70,7 +70,7 @@ module Meshchat
70
70
  end
71
71
 
72
72
  def chat(msg)
73
- message_parts_for(msg) do |time, name, message|
73
+ message_parts_for(msg) do |time, name, message, _|
74
74
  colored_time = (time.to_s + ' ').colorize(:light_magenta)
75
75
  colored_name = (name + ' ').colorize(:cyan)
76
76
 
@@ -79,12 +79,14 @@ module Meshchat
79
79
  end
80
80
 
81
81
  def whisper(msg)
82
- message_parts_for(msg) do |time, name, message|
82
+ message_parts_for(msg) do |time, name, message, to|
83
83
  colored_time = (time.to_s + ' ').colorize(:magenta).bold
84
- colored_name = (name + ' ').colorize(:light_black).bold
84
+ colored_name = name.colorize(:light_black).bold
85
85
  colored_message = message.colorize(:blue).bold
86
+ colored_to = to.colorize(:blue).bold
86
87
 
87
- print_non_destructively(colored_time + colored_name + colored_message)
88
+ names = "#{colored_name}->#{to} "
89
+ print_non_destructively(colored_time + names + colored_message)
88
90
  end
89
91
  end
90
92
 
@@ -94,8 +96,9 @@ module Meshchat
94
96
  time = msg[:time].strftime('%H:%M:%S')
95
97
  name = msg[:from].to_s
96
98
  message = msg[:message]
99
+ to = msg[:to]
97
100
 
98
- yield(time, name, message)
101
+ yield(time, name, message, to)
99
102
  end
100
103
  end
101
104
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Meshchat
3
- VERSION = '0.11.2'
3
+ VERSION = '0.12.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meshchat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.2
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - L. Preston Sego III
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-11 00:00:00.000000000 Z
11
+ date: 2016-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3
@@ -316,6 +316,7 @@ files:
316
316
  - lib/meshchat/ui/cli/keyboard_line_input.rb
317
317
  - lib/meshchat/ui/cli/readline_input.rb
318
318
  - lib/meshchat/ui/command.rb
319
+ - lib/meshchat/ui/command/all_chat_lock.rb
319
320
  - lib/meshchat/ui/command/base.rb
320
321
  - lib/meshchat/ui/command/bind.rb
321
322
  - lib/meshchat/ui/command/chat.rb
@@ -326,6 +327,7 @@ files:
326
327
  - lib/meshchat/ui/command/identity.rb
327
328
  - lib/meshchat/ui/command/import.rb
328
329
  - lib/meshchat/ui/command/irb.rb
330
+ - lib/meshchat/ui/command/node_finder.rb
329
331
  - lib/meshchat/ui/command/offline.rb
330
332
  - lib/meshchat/ui/command/online.rb
331
333
  - lib/meshchat/ui/command/ping.rb
@@ -335,6 +337,7 @@ files:
335
337
  - lib/meshchat/ui/command/server.rb
336
338
  - lib/meshchat/ui/command/share.rb
337
339
  - lib/meshchat/ui/command/whisper.rb
340
+ - lib/meshchat/ui/command/whisper_lock.rb
338
341
  - lib/meshchat/ui/display.rb
339
342
  - lib/meshchat/ui/display/base.rb
340
343
  - lib/meshchat/ui/display/manager.rb
@@ -366,6 +369,6 @@ rubyforge_project:
366
369
  rubygems_version: 2.5.1
367
370
  signing_key:
368
371
  specification_version: 4
369
- summary: Meshchat-0.11.2
372
+ summary: Meshchat-0.12.0
370
373
  test_files: []
371
374
  has_rdoc: