glottis 0.1.1
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/.gitignore +11 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +19 -0
- data/Rakefile +1 -0
- data/bin/console +7 -0
- data/bin/setup +7 -0
- data/exe/glottis +22 -0
- data/glottis.gemspec +30 -0
- data/lib/glottis.rb +2 -0
- data/lib/glottis/client.rb +44 -0
- data/lib/glottis/exceptions/glottis_exception.rb +6 -0
- data/lib/glottis/exceptions/user_exited_exception.rb +8 -0
- data/lib/glottis/handlers/console_input_handler.rb +32 -0
- data/lib/glottis/handlers/console_output_handler.rb +21 -0
- data/lib/glottis/handlers/remote_handler.rb +123 -0
- data/lib/glottis/version.rb +4 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 13566b8129e3820451ffdbeceac479488ee0c7c5
|
4
|
+
data.tar.gz: c35a76b88803bcd3441f13dd67cd513e62fbd1ff
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6c03142ff57480a928bb64ee71a0065dc9fbfcde3fd595111f6978c8633ad54fdccc2b38e146f2fdb6c65f59fc04bb9f077a049d91bbb99d1508ca05afb884f3
|
7
|
+
data.tar.gz: a49d9b2a97e3fd40764964c5ec6dba856235cdd499e22553f8909b7727a868a1c3bacd20c398dfa41d49d48f8a5e4702b90cc7877248b91e9f421444841a9bcf
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# glottis
|
2
|
+
|
3
|
+
A CLI for the [valyx](https://github.com/maxdeliso/valyx) message passing server.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install glottis
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
$ glottis -h
|
12
|
+
|
13
|
+
## Development
|
14
|
+
|
15
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
16
|
+
|
17
|
+
## Contributing
|
18
|
+
|
19
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/maxdeliso/glottis.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/console
ADDED
data/bin/setup
ADDED
data/exe/glottis
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'slop'
|
4
|
+
require 'glottis'
|
5
|
+
|
6
|
+
opts = Slop.parse do |o|
|
7
|
+
o.string '--host', 'a hostname', default: 'localhost'
|
8
|
+
o.integer '--port', 'TCP port', default: 8080
|
9
|
+
o.bool '-v', '--verbose', 'enable verbose mode'
|
10
|
+
o.on '-V', '--version', 'print the version' do
|
11
|
+
puts "glottis #{Glottis::VERSION}"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
o.on '-h', '--help' do
|
15
|
+
puts o
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Glottis::Client.new(opts[:host],
|
21
|
+
opts[:port],
|
22
|
+
verbose: opts[:verbose]).run
|
data/glottis.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'glottis/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'glottis'
|
8
|
+
spec.version = Glottis::VERSION
|
9
|
+
spec.authors = ['Max DeLiso']
|
10
|
+
spec.email = ['maxdeliso@gmail.com']
|
11
|
+
spec.licenses = ['MIT']
|
12
|
+
spec.summary = 'simple http messaging client'
|
13
|
+
spec.homepage = 'https://github.com/maxdeliso/glottis'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
16
|
+
f.match(%r{^(test|spec|features)/})
|
17
|
+
end
|
18
|
+
|
19
|
+
spec.bindir = 'exe'
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_runtime_dependency 'rb-readline', '~> 0.5.3'
|
24
|
+
spec.add_runtime_dependency 'slop', '~> 4.2'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
27
|
+
spec.add_development_dependency 'pry', '~> 0.10.3'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rubocop', '~> 0.35.1'
|
30
|
+
end
|
data/lib/glottis.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'logger'
|
3
|
+
require 'glottis/handlers/console_input_handler'
|
4
|
+
require 'glottis/handlers/console_output_handler'
|
5
|
+
require 'glottis/handlers/remote_handler'
|
6
|
+
|
7
|
+
module Glottis
|
8
|
+
# Client class, used to interact with the host specified.
|
9
|
+
class Client
|
10
|
+
def self.logger
|
11
|
+
@logger ||= Logger.new(STDOUT)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(host, port, opts = {})
|
15
|
+
@host = host
|
16
|
+
@port = port
|
17
|
+
@outgoing = Queue.new
|
18
|
+
@incoming = Queue.new
|
19
|
+
Client.logger.level = opts[:verbose] ? Logger::DEBUG : Logger::WARN
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
Client.logger.info('starting...')
|
24
|
+
Thread.abort_on_exception = true
|
25
|
+
|
26
|
+
@handlers = [
|
27
|
+
Handlers::ConsoleInputHandler.new(@outgoing),
|
28
|
+
Handlers::ConsoleOutputHandler.new(@incoming),
|
29
|
+
Handlers::RemoteHandler.new(@outgoing, @incoming, @host, @port)
|
30
|
+
]
|
31
|
+
|
32
|
+
@handlers.each(&:join)
|
33
|
+
rescue Glottis::Exceptions::UserExitedException
|
34
|
+
Client.logger.info('shutting down...')
|
35
|
+
rescue Errno::ECONNREFUSED => conn_ref
|
36
|
+
Client.logger.error("failed to connect: #{conn_ref}")
|
37
|
+
rescue StandardError => ex
|
38
|
+
Client.logger.warn("shutting down: #{ex}")
|
39
|
+
ensure
|
40
|
+
@handlers.each(&:cleanup)
|
41
|
+
exit(0)
|
42
|
+
end # run
|
43
|
+
end # Client
|
44
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'glottis/exceptions/user_exited_exception'
|
2
|
+
require 'readline'
|
3
|
+
|
4
|
+
module Glottis
|
5
|
+
module Handlers
|
6
|
+
# This class holds a reference to the outgoing message queue,
|
7
|
+
# and posts messages to it from the console as they are entered.
|
8
|
+
class ConsoleInputHandler < Thread
|
9
|
+
USER_PROMPT = '> '.freeze
|
10
|
+
|
11
|
+
def initialize(outgoing)
|
12
|
+
@outgoing = outgoing
|
13
|
+
super do
|
14
|
+
loop do
|
15
|
+
user_input = Readline.readline(USER_PROMPT)
|
16
|
+
Readline::HISTORY.push(user_input)
|
17
|
+
|
18
|
+
# if user_input.nil?
|
19
|
+
# raise Glottis::Exceptions::UserExitedException.new
|
20
|
+
# end
|
21
|
+
|
22
|
+
@outgoing.push(user_input)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def cleanup
|
28
|
+
# do nothing
|
29
|
+
end
|
30
|
+
end # ConsoleInputHandler
|
31
|
+
end # Handlers
|
32
|
+
end # Glottis
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Glottis
|
2
|
+
module Handlers
|
3
|
+
# This class holds a reference to the incoming message queue,
|
4
|
+
# and displays messages in the console as they are received.
|
5
|
+
class ConsoleOutputHandler < Thread
|
6
|
+
def initialize(incoming)
|
7
|
+
@incoming = incoming
|
8
|
+
super do
|
9
|
+
loop do
|
10
|
+
new_msg = @incoming.pop
|
11
|
+
puts "#{new_msg['from']}, #{new_msg['to']}, #{new_msg['msg']}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def cleanup
|
17
|
+
puts '|'
|
18
|
+
end
|
19
|
+
end # ConsoleOutputHandler
|
20
|
+
end # Handlers
|
21
|
+
end # Glottis
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'uri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Glottis
|
7
|
+
module Handlers
|
8
|
+
# This class manages a TCP connection with a valyx server.
|
9
|
+
class RemoteHandler < Thread
|
10
|
+
POLL_INTERVAL = 0.1
|
11
|
+
PROTOCOL = 'http'.freeze
|
12
|
+
|
13
|
+
REMOTE_PATHS = {
|
14
|
+
get_session: '/api/session',
|
15
|
+
get_messages: '/api/messages',
|
16
|
+
post_message: '/api/message'
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
def initialize(outgoing, incoming, host, port)
|
20
|
+
@outgoing = outgoing
|
21
|
+
@incoming = incoming
|
22
|
+
@host = host
|
23
|
+
@port = port
|
24
|
+
@received_count = 0
|
25
|
+
|
26
|
+
setup_http
|
27
|
+
|
28
|
+
super do
|
29
|
+
@http.start
|
30
|
+
request_session
|
31
|
+
|
32
|
+
loop do
|
33
|
+
request_messages
|
34
|
+
send_queued
|
35
|
+
|
36
|
+
sleep POLL_INTERVAL
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def cleanup
|
42
|
+
@http.finish if @http.started?
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def setup_http
|
48
|
+
@http = Net::HTTP.new(@host, @port)
|
49
|
+
# TODO: make these configurable somewhere
|
50
|
+
@http.open_timeout = 1
|
51
|
+
@http.read_timeout = 1
|
52
|
+
@http.continue_timeout = 1
|
53
|
+
end
|
54
|
+
|
55
|
+
def request_session
|
56
|
+
Client.logger.info('making initial request for session...')
|
57
|
+
|
58
|
+
session_req = @http.get(REMOTE_PATHS.fetch(:get_session))
|
59
|
+
|
60
|
+
if Integer(session_req.code) != 201
|
61
|
+
fail("failed to retrieve session: #{response}")
|
62
|
+
end
|
63
|
+
|
64
|
+
response = JSON.parse(session_req.body)
|
65
|
+
|
66
|
+
@sid = response['sid']
|
67
|
+
Client.logger.info("current session id: #{@sid}")
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_messages_from
|
71
|
+
[
|
72
|
+
REMOTE_PATHS.fetch(:get_messages),
|
73
|
+
'?',
|
74
|
+
URI.encode_www_form([['from', @received_count.to_s]])
|
75
|
+
].join
|
76
|
+
end
|
77
|
+
|
78
|
+
# given the result of a .get or .post, converts the response code,
|
79
|
+
# and executes the (side effecting) block if the response was not
|
80
|
+
# successful. calls the block with a message describing the error.
|
81
|
+
def if_not_ok(http_req, ok_code = 200, &b)
|
82
|
+
b.call(http_req.body) if Integer(http_req.code) != ok_code
|
83
|
+
end
|
84
|
+
|
85
|
+
def request_messages
|
86
|
+
Client.logger.debug("polling for messages with with path: #{build_messages_from}")
|
87
|
+
messages_req = @http.get(build_messages_from)
|
88
|
+
|
89
|
+
if_not_ok(messages_req) do |err|
|
90
|
+
Client.logger.error("failed to retrieve messages: #{err}")
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
process_new_messages(messages_req.body)
|
95
|
+
end
|
96
|
+
|
97
|
+
def process_new_messages(messages_data)
|
98
|
+
new_messages = JSON.parse(messages_data)
|
99
|
+
Client.logger.debug("received #{new_messages.size} new messages")
|
100
|
+
@received_count += new_messages.size
|
101
|
+
new_messages.each { |msg| @incoming.push(msg) }
|
102
|
+
end
|
103
|
+
|
104
|
+
def send_queued
|
105
|
+
while @outgoing.size > 0
|
106
|
+
Client.logger.info("processing message with #{@outgoing.size} messages outgoing")
|
107
|
+
|
108
|
+
message_data = {
|
109
|
+
from: @sid,
|
110
|
+
to: '*',
|
111
|
+
msg: @outgoing.pop
|
112
|
+
}.to_json
|
113
|
+
|
114
|
+
post_req = @http.post(REMOTE_PATHS.fetch(:post_message), message_data)
|
115
|
+
|
116
|
+
if_not_ok(post_req) do |err|
|
117
|
+
Client.logger.warn("failed to post message: #{err}")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end # send_queued
|
121
|
+
end # RemoteHandler
|
122
|
+
end # Handlers
|
123
|
+
end # Glottis
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glottis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Max DeLiso
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rb-readline
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.5.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.5.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: slop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.10'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.10.3
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.10.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.35.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.35.1
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- maxdeliso@gmail.com
|
100
|
+
executables:
|
101
|
+
- glottis
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".gitignore"
|
106
|
+
- ".rubocop.yml"
|
107
|
+
- ".travis.yml"
|
108
|
+
- Gemfile
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- bin/console
|
112
|
+
- bin/setup
|
113
|
+
- exe/glottis
|
114
|
+
- glottis.gemspec
|
115
|
+
- lib/glottis.rb
|
116
|
+
- lib/glottis/client.rb
|
117
|
+
- lib/glottis/exceptions/glottis_exception.rb
|
118
|
+
- lib/glottis/exceptions/user_exited_exception.rb
|
119
|
+
- lib/glottis/handlers/console_input_handler.rb
|
120
|
+
- lib/glottis/handlers/console_output_handler.rb
|
121
|
+
- lib/glottis/handlers/remote_handler.rb
|
122
|
+
- lib/glottis/version.rb
|
123
|
+
homepage: https://github.com/maxdeliso/glottis
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 2.4.5.1
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: simple http messaging client
|
147
|
+
test_files: []
|