meshchat 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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) [![Build Status](https://travis-ci.org/NullVoxPopuli/meshchat.svg)](https://travis-ci.org/NullVoxPopuli/meshchat) [![Code Climate](https://codeclimate.com/github/NullVoxPopuli/meshchat/badges/gpa.svg)](https://codeclimate.com/github/NullVoxPopuli/meshchat) [![Test Coverage](https://codeclimate.com/github/NullVoxPopuli/meshchat/badges/coverage.svg)](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
|