meshchat 0.5.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 +7 -0
- data/CHANGELOG.md +1 -0
- data/README.md +7 -0
- data/lib/meshchat.rb +73 -0
- data/lib/meshchat/cli.rb +164 -0
- data/lib/meshchat/cli/command.rb +63 -0
- data/lib/meshchat/cli/config.rb +30 -0
- data/lib/meshchat/cli/exit.rb +9 -0
- data/lib/meshchat/cli/identity.rb +9 -0
- data/lib/meshchat/cli/import.rb +37 -0
- data/lib/meshchat/cli/init.rb +34 -0
- data/lib/meshchat/cli/input.rb +60 -0
- data/lib/meshchat/cli/irb.rb +18 -0
- data/lib/meshchat/cli/listen.rb +9 -0
- data/lib/meshchat/cli/ping.rb +61 -0
- data/lib/meshchat/cli/ping_all.rb +11 -0
- data/lib/meshchat/cli/server.rb +16 -0
- data/lib/meshchat/cli/share.rb +9 -0
- data/lib/meshchat/cli/stop_listening.rb +9 -0
- data/lib/meshchat/cli/whisper.rb +34 -0
- data/lib/meshchat/cli/who.rb +9 -0
- data/lib/meshchat/config/hash_file.rb +75 -0
- data/lib/meshchat/config/settings.rb +112 -0
- data/lib/meshchat/database.rb +30 -0
- data/lib/meshchat/display.rb +32 -0
- data/lib/meshchat/display/base.rb +53 -0
- data/lib/meshchat/display/manager.rb +51 -0
- data/lib/meshchat/encryption.rb +27 -0
- data/lib/meshchat/encryption/aes_rsa.rb +65 -0
- data/lib/meshchat/encryption/passthrough.rb +17 -0
- data/lib/meshchat/instance.rb +34 -0
- data/lib/meshchat/message.rb +38 -0
- data/lib/meshchat/message/base.rb +93 -0
- data/lib/meshchat/message/chat.rb +14 -0
- data/lib/meshchat/message/disconnection.rb +13 -0
- data/lib/meshchat/message/node_list.rb +41 -0
- data/lib/meshchat/message/node_list_diff.rb +15 -0
- data/lib/meshchat/message/node_list_hash.rb +29 -0
- data/lib/meshchat/message/ping.rb +32 -0
- data/lib/meshchat/message/ping_reply.rb +9 -0
- data/lib/meshchat/message/relay.rb +43 -0
- data/lib/meshchat/message/whisper.rb +36 -0
- data/lib/meshchat/models/entry.rb +104 -0
- data/lib/meshchat/net/client.rb +60 -0
- data/lib/meshchat/net/listener/request.rb +48 -0
- data/lib/meshchat/net/listener/request_processor.rb +45 -0
- data/lib/meshchat/net/listener/server.rb +61 -0
- data/lib/meshchat/net/request.rb +29 -0
- data/lib/meshchat/notifier/base.rb +50 -0
- data/lib/meshchat/version.rb +3 -0
- metadata +288 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 01c4f397703dbfd3299712e33207dffb16edfdea
|
4
|
+
data.tar.gz: 2679cafaa50569456444ab222dfd976db1dc724c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f660b1820794d8b40657ae757ae54730ed5c605128781d8f6aa49fd57dc6746a3ac6cd3668e6cddef905f76380a1791da6e072117bdc38d08232f9d697c5dc52
|
7
|
+
data.tar.gz: 923524a79e5fd5f858d48d8a2fb8b6cb53d5b770150f88accc5d2a92132c34f3459952258fb1e8652a0dbea0984bef4b02e78dc9f25a255a12e1242bca80d044
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* Extract meshchat from spiced gracken (spiced gracken may be receiving a rename soon)
|
data/README.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#MeshChat (Ruby) [](https://travis-ci.org/NullVoxPopuli/meshchat) [](https://codeclimate.com/github/NullVoxPopuli/meshchat) [](https://codeclimate.com/github/NullVoxPopuli/meshchat/coverage)
|
2
|
+
|
3
|
+
This is the core functionality for implementing a [mesh-chat](https://github.com/neuravion/mesh-chat) compatible client in ruby
|
4
|
+
|
5
|
+
#Usage
|
6
|
+
|
7
|
+
See [Spiced Gracken](https://github.com/NullVoxPopuli/spiced_gracken)
|
data/lib/meshchat.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# required standard libs
|
2
|
+
require 'openssl'
|
3
|
+
require 'socket'
|
4
|
+
require 'json'
|
5
|
+
require 'date'
|
6
|
+
require 'colorize'
|
7
|
+
require 'curses'
|
8
|
+
require 'io/console'
|
9
|
+
require "readline"
|
10
|
+
|
11
|
+
require 'logger'
|
12
|
+
|
13
|
+
# required gems
|
14
|
+
require 'awesome_print'
|
15
|
+
require 'sqlite3'
|
16
|
+
require 'active_record'
|
17
|
+
require 'curb'
|
18
|
+
require 'thin'
|
19
|
+
require 'libnotify'
|
20
|
+
|
21
|
+
# active support extensions
|
22
|
+
require 'active_support/core_ext/module/delegation'
|
23
|
+
require 'active_support/core_ext/object/blank'
|
24
|
+
require 'active_support/core_ext/object/try'
|
25
|
+
|
26
|
+
# local files for meshchat
|
27
|
+
require 'meshchat/version'
|
28
|
+
require 'meshchat/database'
|
29
|
+
require 'meshchat/instance'
|
30
|
+
require 'meshchat/encryption'
|
31
|
+
require 'meshchat/display'
|
32
|
+
require 'meshchat/display/manager'
|
33
|
+
require 'meshchat/notifier/base'
|
34
|
+
require 'meshchat/models/entry'
|
35
|
+
require 'meshchat/config/hash_file'
|
36
|
+
require 'meshchat/config/settings'
|
37
|
+
require 'meshchat/net/request'
|
38
|
+
require 'meshchat/net/client'
|
39
|
+
require 'meshchat/net/listener/request'
|
40
|
+
require 'meshchat/net/listener/request_processor'
|
41
|
+
require 'meshchat/net/listener/server'
|
42
|
+
require 'meshchat/cli'
|
43
|
+
require 'meshchat/message'
|
44
|
+
|
45
|
+
module MeshChat
|
46
|
+
NAME = 'MeshChat'
|
47
|
+
Settings = Config::Settings
|
48
|
+
Node = Models::Entry
|
49
|
+
Cipher = Encryption
|
50
|
+
Notify = Notifier::Base
|
51
|
+
|
52
|
+
module_function
|
53
|
+
|
54
|
+
# @param [Hash] overrides
|
55
|
+
# @option overrides [Proc] on_display_start what to do upon start of the display manager
|
56
|
+
# @option overrides [class] display the display ui to use inherited from Display::Base
|
57
|
+
def start(overrides = {})
|
58
|
+
defaults = {
|
59
|
+
display: Display::Base,
|
60
|
+
client_name: NAME,
|
61
|
+
client_version: VERSION
|
62
|
+
}
|
63
|
+
options = defaults.merge(overrides)
|
64
|
+
|
65
|
+
# before doing anything, ensure we have a place to store data
|
66
|
+
Database.setup_storage
|
67
|
+
# set the options / overrides!
|
68
|
+
Instance.start(options)
|
69
|
+
end
|
70
|
+
|
71
|
+
def name; Instance.client_name; end
|
72
|
+
def version; Instance.client_version; end
|
73
|
+
end
|
data/lib/meshchat/cli.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'meshchat/cli/input'
|
2
|
+
require 'meshchat/cli/command'
|
3
|
+
require 'meshchat/cli/identity'
|
4
|
+
require 'meshchat/cli/irb'
|
5
|
+
require 'meshchat/cli/config'
|
6
|
+
require 'meshchat/cli/ping'
|
7
|
+
require 'meshchat/cli/ping_all'
|
8
|
+
require 'meshchat/cli/server'
|
9
|
+
require 'meshchat/cli/whisper'
|
10
|
+
require 'meshchat/cli/exit'
|
11
|
+
require 'meshchat/cli/listen'
|
12
|
+
require 'meshchat/cli/stop_listening'
|
13
|
+
require 'meshchat/cli/who'
|
14
|
+
require 'meshchat/cli/init'
|
15
|
+
require 'meshchat/cli/share'
|
16
|
+
require 'meshchat/cli/import'
|
17
|
+
|
18
|
+
module MeshChat
|
19
|
+
# A user interface is responsible for for creating a client
|
20
|
+
# and sending messages to that client
|
21
|
+
class CLI
|
22
|
+
COMMAND_MAP = {
|
23
|
+
Command::CONFIG => CLI::Config,
|
24
|
+
Command::PING => CLI::Ping,
|
25
|
+
Command::PING_ALL => CLI::PingAll,
|
26
|
+
Command::STOP_LISTENING => CLI::StopListening,
|
27
|
+
Command::SERVERS => CLI::Server,
|
28
|
+
Command::SERVER => CLI::Server,
|
29
|
+
Command::EXIT => CLI::Exit,
|
30
|
+
Command::QUIT => CLI::Exit,
|
31
|
+
Command::LISTEN => CLI::Listen,
|
32
|
+
Command::WHO => CLI::Who,
|
33
|
+
Command::IDENTITY => CLI::Identity,
|
34
|
+
Command::IRB => CLI::IRB,
|
35
|
+
Command::INIT => CLI::Init,
|
36
|
+
Command::SHARE => CLI::Share,
|
37
|
+
Command::IMPORT => CLI::Import,
|
38
|
+
Command::EXPORT => CLI::Share
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
class << self
|
43
|
+
|
44
|
+
delegate :server_location, :listen_for_commands,
|
45
|
+
:shutdown, :start_server, :client, :server,
|
46
|
+
:check_startup_settings, :create_input, :close_server,
|
47
|
+
to: :instance
|
48
|
+
|
49
|
+
def instance
|
50
|
+
@instance ||= new
|
51
|
+
end
|
52
|
+
|
53
|
+
# TODO: extract this for sub commands
|
54
|
+
def autocompletes
|
55
|
+
commands = COMMAND_MAP.map{ |k, v| "/#{k}" }
|
56
|
+
aliases = MeshChat::Node.all.map{ |n| "#{n.alias_name}" }
|
57
|
+
commands + aliases
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def initialize
|
64
|
+
# Set up auto complete
|
65
|
+
completion = proc{ |s| self.class.autocompletes.grep(/^#{Regexp.escape(s)}/) }
|
66
|
+
Readline.completion_proc = completion
|
67
|
+
|
68
|
+
# this will allow our listener / server to print exceptions,
|
69
|
+
# rather than silently fail
|
70
|
+
Thread.abort_on_exception = true
|
71
|
+
end
|
72
|
+
|
73
|
+
def listen_for_commands
|
74
|
+
process_input while true
|
75
|
+
end
|
76
|
+
|
77
|
+
def process_input
|
78
|
+
msg = get_input
|
79
|
+
create_input(msg)
|
80
|
+
rescue SystemExit, Interrupt
|
81
|
+
close_program
|
82
|
+
rescue Exception => e
|
83
|
+
Display.error e.class.name
|
84
|
+
Display.error e.message.colorize(:red)
|
85
|
+
Display.error e.backtrace.join("\n").colorize(:red)
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_input(msg)
|
89
|
+
handler = Input.create(msg)
|
90
|
+
handler.handle
|
91
|
+
rescue => e
|
92
|
+
Display.error e.message
|
93
|
+
Display.error e.class.name
|
94
|
+
Display.error e.backtrace.join("\n").colorize(:red)
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def get_input
|
99
|
+
Readline.readline('> ', true)
|
100
|
+
end
|
101
|
+
|
102
|
+
def start_server
|
103
|
+
|
104
|
+
unless Settings.valid?
|
105
|
+
Display.alert("settings not fully valid\n")
|
106
|
+
errors = Settings.errors
|
107
|
+
errors.each do |error|
|
108
|
+
Display.alert(" - #{error}")
|
109
|
+
end
|
110
|
+
|
111
|
+
if errors.present?
|
112
|
+
Display.info('set these with /config set <field> <value>')
|
113
|
+
end
|
114
|
+
|
115
|
+
return
|
116
|
+
end
|
117
|
+
|
118
|
+
Thread.abort_on_exception = false
|
119
|
+
Thin::Logging.silent = true
|
120
|
+
|
121
|
+
Thread.new do
|
122
|
+
MeshChat::Net::Listener::Server.run!(
|
123
|
+
port: MeshChat::Settings['port'],
|
124
|
+
# logger: MeshChat::Display,
|
125
|
+
show_exceptions: true,
|
126
|
+
server: :thin,
|
127
|
+
dump_errors: true,
|
128
|
+
threaded: true
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def close_server
|
135
|
+
puts 'shutting down server'
|
136
|
+
if @server.present?
|
137
|
+
server = @server.pop
|
138
|
+
server.try(:server).try(:close)
|
139
|
+
end
|
140
|
+
puts 'no longer listening...'
|
141
|
+
end
|
142
|
+
|
143
|
+
def server_location
|
144
|
+
Settings.location
|
145
|
+
end
|
146
|
+
|
147
|
+
def check_startup_settings
|
148
|
+
start_server if Settings['autolisten']
|
149
|
+
end
|
150
|
+
|
151
|
+
def close_program
|
152
|
+
exit
|
153
|
+
end
|
154
|
+
|
155
|
+
# save config and exit
|
156
|
+
def shutdown
|
157
|
+
# close_server
|
158
|
+
Display.info 'saving config...'
|
159
|
+
Settings.save
|
160
|
+
Display.alert "\n\nGoodbye. \n\nThank you for using #{MeshChat.name}"
|
161
|
+
exit
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module MeshChat
|
2
|
+
class CLI
|
3
|
+
class Command < CLI::Input
|
4
|
+
attr_accessor :_input
|
5
|
+
|
6
|
+
# Commands
|
7
|
+
SET = 'set'
|
8
|
+
CONFIG = 'config'
|
9
|
+
DISPLAY = 'display'
|
10
|
+
EXIT = 'exit'
|
11
|
+
QUIT = 'quit'
|
12
|
+
LISTEN = 'listen'
|
13
|
+
STOP_LISTENING = 'stoplistening'
|
14
|
+
CONNECT = 'connect'
|
15
|
+
CHAT = 'chat'
|
16
|
+
ADD = 'add'
|
17
|
+
REMOVE = 'remove'
|
18
|
+
RM = 'rm'
|
19
|
+
SERVERS = 'servers'
|
20
|
+
SERVER = 'server'
|
21
|
+
WHO = 'who'
|
22
|
+
PING = 'ping'
|
23
|
+
PING_ALL = 'pingall'
|
24
|
+
IDENTITY = 'identity'
|
25
|
+
IRB = 'c'
|
26
|
+
INIT = 'init'
|
27
|
+
SHARE = 'share'
|
28
|
+
IMPORT = 'import'
|
29
|
+
EXPORT = 'export'
|
30
|
+
|
31
|
+
def handle
|
32
|
+
klass = CLI::COMMAND_MAP[command]
|
33
|
+
if klass
|
34
|
+
klass.new(_input).handle
|
35
|
+
else
|
36
|
+
Display.alert 'not implemented...'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def command_string
|
43
|
+
@command_string ||= _input[1, _input.length]
|
44
|
+
end
|
45
|
+
|
46
|
+
def command_args
|
47
|
+
@command_args ||= command_string.split(' ')
|
48
|
+
end
|
49
|
+
|
50
|
+
def command
|
51
|
+
@command ||= command_args.first
|
52
|
+
end
|
53
|
+
|
54
|
+
def sub_command_args
|
55
|
+
@sub_command_args ||= command_args[2..3]
|
56
|
+
end
|
57
|
+
|
58
|
+
def sub_command
|
59
|
+
@sub_command ||= command_args[1]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module MeshChat
|
2
|
+
class CLI
|
3
|
+
class Config < CLI::Command
|
4
|
+
def handle
|
5
|
+
case sub_command
|
6
|
+
when SET
|
7
|
+
if is_valid_set_command?
|
8
|
+
key, value = config_set_args
|
9
|
+
|
10
|
+
Display.info Settings.set(key, with: value)
|
11
|
+
else
|
12
|
+
Display.alert 'set requires a key and a value'
|
13
|
+
end
|
14
|
+
when DISPLAY
|
15
|
+
Display.info Settings.display
|
16
|
+
else
|
17
|
+
Display.alert 'config command not implemented...'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def config_set_args
|
22
|
+
command_args[2..3]
|
23
|
+
end
|
24
|
+
|
25
|
+
def is_valid_set_command?
|
26
|
+
sub_command == SET && command_args.length == 4
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module MeshChat
|
2
|
+
class CLI
|
3
|
+
class Import < CLI::Command
|
4
|
+
def handle
|
5
|
+
if command_valid?
|
6
|
+
node = Models::Entry.import_from_file(filename)
|
7
|
+
if node.valid? && node.persisted?
|
8
|
+
Display.success "#{node.alias_name} successfully imported"
|
9
|
+
|
10
|
+
# send the server list to this new node
|
11
|
+
Net::Client.send(
|
12
|
+
node: node,
|
13
|
+
message: Message::NodeList.new
|
14
|
+
)
|
15
|
+
else
|
16
|
+
Display.alert "#{node.alias_name} is invalid"
|
17
|
+
Display.alert node.errors.full_messages.join("\n")
|
18
|
+
end
|
19
|
+
else
|
20
|
+
Display.alert usage
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def usage
|
25
|
+
'Usage: /import {filename}'
|
26
|
+
end
|
27
|
+
|
28
|
+
def command_valid?
|
29
|
+
filename.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def filename
|
33
|
+
sub_command
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module MeshChat
|
2
|
+
class CLI
|
3
|
+
class Init < CLI::Command
|
4
|
+
def handle
|
5
|
+
if Settings.uid_exists?
|
6
|
+
if confirm? 'uid exists, are you sure you want a new identity?'
|
7
|
+
Settings.generate_uid
|
8
|
+
else
|
9
|
+
Display.alert 'uid generation aborted'
|
10
|
+
end
|
11
|
+
else
|
12
|
+
Settings.generate_uid
|
13
|
+
end
|
14
|
+
|
15
|
+
if Settings.keys_exist?
|
16
|
+
if confirm? 'keys exist, overwrite?'
|
17
|
+
Settings.generate_keys
|
18
|
+
else
|
19
|
+
Display.alert 'key generation aborted'
|
20
|
+
end
|
21
|
+
else
|
22
|
+
Settings.generate_keys
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def confirm?(msg)
|
27
|
+
Display.warning(msg + ' (Y/N)')
|
28
|
+
response = gets
|
29
|
+
response = response.chomp
|
30
|
+
['yes', 'y'].include?(response.downcase)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|