ruby-dovado 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +20 -0
- data/README.md +60 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/lib/dovado.rb +22 -0
- data/lib/dovado/client.rb +154 -0
- data/lib/dovado/connection_error.rb +5 -0
- data/lib/dovado/router.rb +96 -0
- data/lib/dovado/router/info.rb +98 -0
- data/lib/dovado/router/info/operator.rb +82 -0
- data/lib/dovado/router/info/operator/telia.rb +23 -0
- data/lib/dovado/router/services.rb +76 -0
- data/lib/dovado/router/sms.rb +97 -0
- data/lib/dovado/router/sms/message.rb +92 -0
- data/lib/dovado/router/sms/messages.rb +39 -0
- data/lib/dovado/utilities.rb +41 -0
- data/lib/dovado/version.rb +4 -0
- data/ruby-dovado.gemspec +28 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 493334755f4182fb4c6ffbf010747a6212f48352
|
4
|
+
data.tar.gz: 67798f1509b7ad86e95dd321a92267a0fd8a80f4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9ffe73cdf1b1a4b89f85c006d7597ad0fb0410614fc542c3bce3dfb62a917b031194a955be6aa26f2c06fb63bbc78762732f3c6e160f9aa072b0bd0f71b80dfd
|
7
|
+
data.tar.gz: bbf0eed5cd3ee58b89cc52642eb1b7d6a7a35eaf9158d1587cf09f1e0b9bcfcd0f1239505963cd830e9c971b3de48fa2548c95ec559cfffbe0a3025be4c31d9b
|
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.2
|
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015 Jan Lindblom
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Ruby-Dovado
|
2
|
+
|
3
|
+
A Dovado Router API for Ruby.
|
4
|
+
|
5
|
+
[![Build Status](https://drone.io/bitbucket.org/janlindblom/ruby-dovado/status.png)](https://drone.io/bitbucket.org/janlindblom/ruby-dovado/latest)
|
6
|
+
|
7
|
+
This library serves to enable easy access to the built in, Telnet-based, rudimentary API of the [routers from Dovado](http://www.dovado.com/en/products) running software version 6 and 7 (applies to the original Tiny and Go routers, among others). It might work with software version 8 routers (the Tiny AC) too but I have no means to test against that since I don't have one of the later routers.
|
8
|
+
|
9
|
+
## Purpose
|
10
|
+
|
11
|
+
The original purpose of this library was to enable addition of router information about connection state, mobile data connection quality and data quota usage on a wall-mounted TV or a small touch screen connected to a Raspberry Pi, accessing a dashboard implemented using [Dashing](https://shopify.github.io/dashing/).
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Add it to your Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem "ruby-dovado"
|
19
|
+
```
|
20
|
+
|
21
|
+
They load it in your code:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require "dovado"
|
25
|
+
|
26
|
+
router = Dovado::Router.new(address: "192.168.0.1", user: "admin", password: "password")
|
27
|
+
router.info
|
28
|
+
router.sms.load_messages
|
29
|
+
message = router.sms.get_message 12
|
30
|
+
```
|
31
|
+
|
32
|
+
## Design Considerations
|
33
|
+
|
34
|
+
Since the API published by these routers is Telnet-based, it stands to reason to limit simultaneous connections. This is achieved by a single client object implemented as a Celluloid Actor. The reason for this is because Celluloid Actor objects can be supervised, block threads and be accessed from multiple threads simultaneously without the need to implement any special locking or waiting mechanisms.
|
35
|
+
|
36
|
+
Additionally, all replies are cached internally to limit the number of calls to the router API. This is done because the API is rather slow which would make any calls using this library wait for several seconds for a reply. These replies are cached inside Celluloid actors so that multiple, seemingly parallel requests will get the same response object. Caching can be overridden by forcing the call through to the router. Otherwise, the reply becomes invalid within a couple of seconds so that the next call will go through to the router and fetch any updates. Think of it as a cheap rate-limiter.
|
37
|
+
|
38
|
+
## Copyright
|
39
|
+
|
40
|
+
Ruby-Dovado © 2015 by [Jan Lindblom](mailto:janlindblom@fastmail.fm).
|
41
|
+
Ruby-Dovado is licensed under the MIT license. Please see the
|
42
|
+
{file:LICENSE.txt} file for more information.
|
43
|
+
|
44
|
+
The Dovado, Dovado Tiny, Dovado Go, Dovado Tiny AC et.al brands are © 2004 - 2015 Dovado FZ-LLC.
|
45
|
+
|
46
|
+
This library is neither endorsed nor supported by Dovado.
|
47
|
+
|
48
|
+
## Development
|
49
|
+
|
50
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
51
|
+
|
52
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
53
|
+
|
54
|
+
## Contributing
|
55
|
+
|
56
|
+
1. Fork it ( https://bitbucket.org/janlindblom/ruby-dovado/fork )
|
57
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
58
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
59
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
60
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "yard"
|
4
|
+
require "yard/rake/yardoc_task"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
|
7
|
+
desc "Run RSpec code examples"
|
8
|
+
namespace :spec do
|
9
|
+
desc "Run offline RSpec code examples"
|
10
|
+
RSpec::Core::RakeTask.new(:offline) do |t|
|
11
|
+
t.rspec_opts = "--tag offline"
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Run online RSpec code examples"
|
15
|
+
RSpec::Core::RakeTask.new(:online) do |t|
|
16
|
+
t.rspec_opts = "--tag online"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run all RSpec code examples"
|
20
|
+
RSpec::Core::RakeTask.new(:all) do |t|
|
21
|
+
t.rspec_opts = "--tag offline --tag online"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
YARD::Rake::YardocTask.new do |t|
|
26
|
+
t.files = ['lib/**/*.rb']
|
27
|
+
t.stats_options = ['--list-undoc']
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => "spec:offline"
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/dovado.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'celluloid/current'
|
2
|
+
|
3
|
+
require 'dovado/connection_error'
|
4
|
+
require 'dovado/utilities'
|
5
|
+
require 'dovado/client'
|
6
|
+
|
7
|
+
require 'dovado/router'
|
8
|
+
require 'dovado/router/services'
|
9
|
+
require 'dovado/router/info'
|
10
|
+
require 'dovado/router/info/operator'
|
11
|
+
require 'dovado/router/info/operator/telia'
|
12
|
+
|
13
|
+
require 'dovado/router/sms'
|
14
|
+
require 'dovado/router/sms/messages'
|
15
|
+
require 'dovado/router/sms/message'
|
16
|
+
|
17
|
+
# The Ruby-Dovado library.
|
18
|
+
#
|
19
|
+
# @author Jan Lindblom <janlindblom@fastmail.fm>
|
20
|
+
# @version 1.0.0
|
21
|
+
module Dovado
|
22
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'net/telnet'
|
2
|
+
|
3
|
+
module Dovado
|
4
|
+
# Internal API client.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since 1.0.0
|
8
|
+
class Client
|
9
|
+
include Celluloid
|
10
|
+
|
11
|
+
# Create a new {Client} object.
|
12
|
+
#
|
13
|
+
# The default options are:
|
14
|
+
# - Address: 192.168.0.1
|
15
|
+
# - Port: 6435
|
16
|
+
# - User: admin
|
17
|
+
# - Password: password
|
18
|
+
#
|
19
|
+
# @param [Hash] args option arguments.
|
20
|
+
# @option args [String] :server The server (router) address.
|
21
|
+
# @option args [Integer] :port The server (router) port.
|
22
|
+
# @option args [String] :user The user name.
|
23
|
+
# @option args [String] :password The user password.
|
24
|
+
def initialize(args=nil)
|
25
|
+
# Defaults
|
26
|
+
@address = '192.168.0.1'
|
27
|
+
@user = 'admin'
|
28
|
+
@password = 'password'
|
29
|
+
@port = 6435
|
30
|
+
unless args.nil?
|
31
|
+
@address = args[:server] if args.has_key? :server
|
32
|
+
@port = args[:port] if args.has_key? :port
|
33
|
+
@user = args[:user] if args.has_key? :user
|
34
|
+
@password = args[:password] if args.has_key? :password
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Run a command on the router.
|
39
|
+
#
|
40
|
+
# @param [String] text the command to run.
|
41
|
+
# @raise [ConnectionError] if there is an error in the communication with
|
42
|
+
# the router.
|
43
|
+
def command(text=nil)
|
44
|
+
perform_command text
|
45
|
+
rescue IOError
|
46
|
+
disconnect
|
47
|
+
connect unless connected?
|
48
|
+
authenticate unless authenticated?
|
49
|
+
perform_command text
|
50
|
+
rescue Net::ReadTimeout => ex
|
51
|
+
disconnect
|
52
|
+
connect unless connected?
|
53
|
+
authenticate unless authenticated?
|
54
|
+
perform_command text
|
55
|
+
#raise ConnectionError.new "Error connecting to router: #{ex.message}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Connect to the router.
|
59
|
+
# @raise [ConnectionError] if there is an error in the communication with
|
60
|
+
# the router.
|
61
|
+
def connect
|
62
|
+
if @server.nil?
|
63
|
+
@server = Net::Telnet.new(
|
64
|
+
'Host' => @address,
|
65
|
+
'Port' => @port,
|
66
|
+
'Telnetmode' => false,
|
67
|
+
'Prompt' => />>\s/)
|
68
|
+
end
|
69
|
+
rescue IOError
|
70
|
+
disconnect
|
71
|
+
raise ConnectionError.new "Error connecting to router: #{ex.message}"
|
72
|
+
rescue Net::ReadTimeout => ex
|
73
|
+
disconnect
|
74
|
+
raise ConnectionError.new "Error connecting to router: #{ex.message}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Disconnect from the router.
|
78
|
+
def disconnect
|
79
|
+
unless @server.nil?
|
80
|
+
@server.cmd "quit"
|
81
|
+
@server.close
|
82
|
+
end
|
83
|
+
@authenticated = false
|
84
|
+
@server = nil
|
85
|
+
end
|
86
|
+
|
87
|
+
# Check if we are connected to the router.
|
88
|
+
#
|
89
|
+
# @return [Boolean] +true+ or +false+.
|
90
|
+
def connected?
|
91
|
+
unless @server.nil?
|
92
|
+
true
|
93
|
+
else
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Authenticate user.
|
99
|
+
#
|
100
|
+
# @todo Verify authentication properly.
|
101
|
+
# @raise [ConnectionError] if there is an error in the communication with
|
102
|
+
# the router.
|
103
|
+
def authenticate
|
104
|
+
perform_authentication
|
105
|
+
rescue IOError
|
106
|
+
disconnect
|
107
|
+
connect unless connected?
|
108
|
+
perform_authentication
|
109
|
+
rescue Net::ReadTimeout => ex
|
110
|
+
disconnect
|
111
|
+
connect unless connected?
|
112
|
+
perform_authentication
|
113
|
+
#raise ConnectionError.new "Error connecting to router: #{ex.message}"
|
114
|
+
end
|
115
|
+
|
116
|
+
# Check if we're authenticated.
|
117
|
+
#
|
118
|
+
# @return [Boolean] +true+ or +false+.
|
119
|
+
def authenticated?
|
120
|
+
@authenticated
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def perform_command(text)
|
126
|
+
unless text.nil?
|
127
|
+
res = @server.puts(text)
|
128
|
+
res = @server.waitfor(/>>\s/)
|
129
|
+
res
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def perform_authentication
|
134
|
+
if connected?
|
135
|
+
unless authenticated?
|
136
|
+
raise ArgumentError.new "Username cannot be nil" if @user.nil?
|
137
|
+
raise ArgumentError.new "Password cannot be nil" if @password.nil?
|
138
|
+
|
139
|
+
@server.cmd "user #{@user}"
|
140
|
+
@server.waitfor />>\s/
|
141
|
+
@server.cmd "pass #{@password}"
|
142
|
+
|
143
|
+
# TODO: verify authentication for real.
|
144
|
+
@authenticated = true
|
145
|
+
else
|
146
|
+
@authenticated = false
|
147
|
+
end
|
148
|
+
else
|
149
|
+
@authenticated = false
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Dovado
|
2
|
+
# A Dovado Router.
|
3
|
+
#
|
4
|
+
# @since 1.0.0
|
5
|
+
class Router
|
6
|
+
include Celluloid
|
7
|
+
|
8
|
+
# Create a new {Router} object representing an actual Dovado router on the local
|
9
|
+
# network.
|
10
|
+
#
|
11
|
+
# The default router options are:
|
12
|
+
# - Address: 192.168.0.1
|
13
|
+
# - Port: 6435
|
14
|
+
# - User: admin
|
15
|
+
# - Password: password
|
16
|
+
#
|
17
|
+
# @param [Hash] args optional arguments.
|
18
|
+
# @option args [String] :address IP address or DNS name
|
19
|
+
# @option args [Integer] :port Port which the router is listening on
|
20
|
+
# @option args [String] :user User name
|
21
|
+
# @option args [String] :password Password
|
22
|
+
def initialize(args=nil)
|
23
|
+
@address = '192.168.0.1' # Default address
|
24
|
+
@port = 6435
|
25
|
+
user = "admin" # Default username
|
26
|
+
password = "password" # Default password
|
27
|
+
@connected = false
|
28
|
+
unless args.nil?
|
29
|
+
@address = args[:address] if args.has_key? :address and !args[:address].nil?
|
30
|
+
@port = args[:port] if args.has_key? :port and !args[:port].nil?
|
31
|
+
user = args[:user] if args.has_key? :user and !args[:user].nil?
|
32
|
+
password = args[:password] if args.has_key? :password and !args[:password].nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
Client.supervise as: :client, size: 1, args: [{
|
36
|
+
server: @address,
|
37
|
+
port: @port,
|
38
|
+
user: user,
|
39
|
+
password: password
|
40
|
+
}]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Fetch services information from the router.
|
44
|
+
#
|
45
|
+
# @return [Services] The {Services} object
|
46
|
+
# @see {Services}
|
47
|
+
def services
|
48
|
+
Services.supervise as: :router_services, size: 1 unless Actor[:router_services]
|
49
|
+
client = Actor[:client]
|
50
|
+
router_services = Actor[:router_services]
|
51
|
+
|
52
|
+
unless router_services.valid?
|
53
|
+
client.connect unless client.connected?
|
54
|
+
client.authenticate unless client.authenticated?
|
55
|
+
string = client.command('services')
|
56
|
+
router_services.create_from_string string
|
57
|
+
end
|
58
|
+
|
59
|
+
if router_services[:sms] == 'enabled'
|
60
|
+
|
61
|
+
Sms.supervise as: :sms, size: 1 unless Actor[:sms]
|
62
|
+
sms.enabled = true
|
63
|
+
end
|
64
|
+
router_services
|
65
|
+
end
|
66
|
+
|
67
|
+
# Fetch information from the router.
|
68
|
+
#
|
69
|
+
# @return [Info] The {Info} object.
|
70
|
+
# @see {Info}
|
71
|
+
def info
|
72
|
+
Info.supervise as: :router_info, size: 1 unless Actor[:router_info]
|
73
|
+
router_info = Actor[:router_info]
|
74
|
+
client = Actor[:client]
|
75
|
+
router_info = Actor[:router_info]
|
76
|
+
unless router_info.valid?
|
77
|
+
client.connect unless client.connected?
|
78
|
+
client.authenticate unless client.authenticated?
|
79
|
+
info = client.command('info')
|
80
|
+
router_info.create_from_string info
|
81
|
+
end
|
82
|
+
services
|
83
|
+
router_info
|
84
|
+
end
|
85
|
+
|
86
|
+
# Fetch text messages from the router.
|
87
|
+
#
|
88
|
+
# @return [Sms] The {Sms} object.
|
89
|
+
# @see {Sms}
|
90
|
+
def sms
|
91
|
+
Sms.supervise as: :sms, size: 1 unless Actor[:sms]
|
92
|
+
Actor[:sms]
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
require 'socket'
|
4
|
+
require 'thread_safe'
|
5
|
+
|
6
|
+
module Dovado
|
7
|
+
class Router
|
8
|
+
# Router information.
|
9
|
+
#
|
10
|
+
# @since 1.0.0
|
11
|
+
class Info
|
12
|
+
include Celluloid
|
13
|
+
|
14
|
+
# Create a new {Info} object.
|
15
|
+
#
|
16
|
+
# @param [Hash] args optional hash to initialize with.
|
17
|
+
def initialize(args=nil)
|
18
|
+
# Defaults
|
19
|
+
@data = ThreadSafe::Cache.new
|
20
|
+
|
21
|
+
@last_update = nil
|
22
|
+
unless args.nil?
|
23
|
+
@data = args
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a new {Info} object from a +String+.
|
28
|
+
#
|
29
|
+
# @param [String] data_string router information string from the router.
|
30
|
+
def create_from_string(data_string=nil)
|
31
|
+
unless Actor[:sms]
|
32
|
+
Sms.supervise as: :sms, size: 1
|
33
|
+
end
|
34
|
+
sms = Actor[:sms]
|
35
|
+
data_array = data_string.split("\n")
|
36
|
+
data_array.each do |data_entry|
|
37
|
+
entry_array = data_entry.split('=')
|
38
|
+
if entry_array.length == 2
|
39
|
+
key = entry_array[0].downcase
|
40
|
+
val = entry_array[1]
|
41
|
+
keysym = Utilities.name_to_sym(key)
|
42
|
+
case key
|
43
|
+
when 'traffic_modem_tx'
|
44
|
+
@data[:traffic_modem_tx] = val.strip.to_i
|
45
|
+
when 'traffic_modem_rx'
|
46
|
+
@data[:traffic_modem_rx] = val.strip.to_i
|
47
|
+
when 'time'
|
48
|
+
@data[:time] = Time.parse(val)
|
49
|
+
when 'date'
|
50
|
+
@data[:date] = Date.parse(val)
|
51
|
+
when 'sms_unread'
|
52
|
+
@data[:sms] = sms if @data[:sms].nil?
|
53
|
+
@data[:sms].unread = val.to_i
|
54
|
+
when 'sms_total'
|
55
|
+
@data[:sms] = sms if @data[:sms].nil?
|
56
|
+
@data[:sms].total = val.to_i
|
57
|
+
when 'connected_devices'
|
58
|
+
val = val.split(',')
|
59
|
+
@data[keysym] = val
|
60
|
+
else
|
61
|
+
@data[keysym] = val
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
touch!
|
66
|
+
end
|
67
|
+
|
68
|
+
# Determine if this info object is valid.
|
69
|
+
#
|
70
|
+
# @return [Boolean] true or false.
|
71
|
+
def valid?
|
72
|
+
return false if @last_update.nil?
|
73
|
+
(@last_update + SecureRandom.random_number(9) + 1 <= Time.now.to_i)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Fetch an entry from the {Info} object.
|
77
|
+
#
|
78
|
+
# @param [Symbol] key The key to fetch.
|
79
|
+
def [](key)
|
80
|
+
@data[key]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Fetch the list of entries in the {Info} object.
|
84
|
+
#
|
85
|
+
# @return [Array<Symbol>]
|
86
|
+
def keys
|
87
|
+
@data.keys
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def touch!
|
93
|
+
@last_update = Time.now.to_i
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Dovado
|
2
|
+
class Router
|
3
|
+
class Info
|
4
|
+
# An ISP/operator.
|
5
|
+
#
|
6
|
+
# Extend this class to create a new operator or use it as it is.
|
7
|
+
#
|
8
|
+
# @example Extending the Operator class
|
9
|
+
# class MyOperator < Dovado::Router::Info::Operator
|
10
|
+
# def initialize
|
11
|
+
# super(name: "MyOperator", number: "s1234", commands: {data_remaining: "quota"})
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# @example Using the Operator class as it is
|
16
|
+
# my_operator = Dovado::Router::Info::Operator.new(name: "MyOperator", number: "s1234", commands: {data_remaining: "quota"})
|
17
|
+
#
|
18
|
+
# @since 1.0.0
|
19
|
+
class Operator
|
20
|
+
include Celluloid
|
21
|
+
|
22
|
+
# Number to send messages to for the operator.
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :number
|
25
|
+
# Name of the operator.
|
26
|
+
# @return [String]
|
27
|
+
attr_accessor :name
|
28
|
+
# List of commands supported by the operator.
|
29
|
+
# @return [Hash]
|
30
|
+
attr_accessor :commands
|
31
|
+
|
32
|
+
# Create a new Operator object.
|
33
|
+
#
|
34
|
+
# @example Initializing with custom commands
|
35
|
+
# my_commands = { data_remaining: "datamängd".encode("UTF-8") }
|
36
|
+
# my_operator = Operator.new(name: "MyOperator", number: "s1234", commands: my_commands)
|
37
|
+
#
|
38
|
+
# @param [Hash] args optional arguments
|
39
|
+
# @option args [String] :number The recipient number for this operator.
|
40
|
+
# Use the prefix +s+ to indicate a "short" number, e.g "s4466".
|
41
|
+
# @option args [String] :name Name of the operator.
|
42
|
+
# @option args [Hash] :commands Supported commands.
|
43
|
+
def initialize(args=nil)
|
44
|
+
self.name = "Unknown"
|
45
|
+
unless args.nil?
|
46
|
+
@number = ""
|
47
|
+
@name = "NoOperator"
|
48
|
+
@commands = Operator.default_commands
|
49
|
+
@number = args[:number] unless args[:number].nil?
|
50
|
+
@name = args[:name] unless args[:name].nil?
|
51
|
+
unless args[:commands].nil?
|
52
|
+
missing_keys = []
|
53
|
+
Operator.required_commands.each do |req|
|
54
|
+
missing_keys << req unless args[:commands].has_key?(req)
|
55
|
+
end
|
56
|
+
raise ArgumentError.new "Missing required keys in hash: #{Utilities.array_to_sentence(missing_keys)}" unless missing_keys.empty?
|
57
|
+
@commands = args[:commands]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Default commands for an operator.
|
63
|
+
def self.default_commands
|
64
|
+
commands = {}
|
65
|
+
required_commands.each do |command|
|
66
|
+
commands[command] = ""
|
67
|
+
end
|
68
|
+
commands
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def self.required_commands
|
74
|
+
[
|
75
|
+
:data_remaining
|
76
|
+
]
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "thread_safe"
|
2
|
+
|
3
|
+
module Dovado
|
4
|
+
class Router
|
5
|
+
class Info
|
6
|
+
class Operator
|
7
|
+
# The Swedish operator Telia.
|
8
|
+
#
|
9
|
+
# @since 1.0.0
|
10
|
+
class Telia < Operator
|
11
|
+
|
12
|
+
# Create a new Telia Operator object.
|
13
|
+
def initialize
|
14
|
+
super(name: "Telia", number: "s4466", commands: {
|
15
|
+
data_remaining: 'datamängd'.encode('UTF-8')
|
16
|
+
})
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "time"
|
2
|
+
require "thread_safe"
|
3
|
+
|
4
|
+
module Dovado
|
5
|
+
class Router
|
6
|
+
# Router Services.
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
class Services
|
10
|
+
include Celluloid
|
11
|
+
|
12
|
+
# Create a new {Services} object.
|
13
|
+
#
|
14
|
+
# @param [Hash] args optional argiments
|
15
|
+
def initialize(args=nil)
|
16
|
+
@list = ThreadSafe::Cache.new
|
17
|
+
@last_update = nil
|
18
|
+
unless args.nil?
|
19
|
+
args.each do |k,v|
|
20
|
+
@list[Utilities.name_to_sym(k)] = v
|
21
|
+
end
|
22
|
+
touch!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create a new {Services} object from a string with values from the router
|
27
|
+
# API.
|
28
|
+
#
|
29
|
+
# @param [String] data_string +String+ with data from fetched from the
|
30
|
+
# router.
|
31
|
+
# @return [Services] a new {Services} object.
|
32
|
+
def create_from_string(data_string=nil)
|
33
|
+
data_array = data_string.split("\n")
|
34
|
+
data_array.each do |data_entry|
|
35
|
+
entry_array = data_entry.split('=')
|
36
|
+
if entry_array.length == 2
|
37
|
+
key = entry_array[0].downcase
|
38
|
+
val = entry_array[1]
|
39
|
+
keysym = Utilities.name_to_sym(key)
|
40
|
+
@list[keysym] = val
|
41
|
+
end
|
42
|
+
end
|
43
|
+
touch!
|
44
|
+
end
|
45
|
+
|
46
|
+
# Fetch an entry from the {Services} object.
|
47
|
+
#
|
48
|
+
# @param [Symbol] key The key to fetch.
|
49
|
+
def [](key)
|
50
|
+
@list[key]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Fetch the list of entries in the {Services} object.
|
54
|
+
#
|
55
|
+
# @return [Array<Symbol>]
|
56
|
+
def keys
|
57
|
+
@list.keys
|
58
|
+
end
|
59
|
+
|
60
|
+
# Checks if this {Services} object is still valid.
|
61
|
+
#
|
62
|
+
# @return [Boolean] +true+ or +false+.
|
63
|
+
def valid?
|
64
|
+
return false if @last_update.nil?
|
65
|
+
(@last_update + SecureRandom.random_number(9) + 1 <= Time.now.to_i)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def touch!
|
71
|
+
@last_update = Time.now.to_i
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Dovado
|
2
|
+
class Router
|
3
|
+
# Text messages.
|
4
|
+
#
|
5
|
+
# @since 1.0.0
|
6
|
+
class Sms
|
7
|
+
include Celluloid
|
8
|
+
|
9
|
+
# Unread messages.
|
10
|
+
# @return [Integer] number of unread
|
11
|
+
attr_accessor :unread
|
12
|
+
# Total number of messages.
|
13
|
+
# @return [Integer] total number of messages
|
14
|
+
attr_accessor :total
|
15
|
+
# Is the SMS handler enabled?
|
16
|
+
# @return [Boolean] +true+ or +false+
|
17
|
+
attr_accessor :enabled
|
18
|
+
# Message Id's.
|
19
|
+
# @return [Array] list of message Id's
|
20
|
+
attr_accessor :ids
|
21
|
+
|
22
|
+
# Create a new {Sms} object.
|
23
|
+
#
|
24
|
+
# @param [Hash] args optional arguments.
|
25
|
+
# @option args [Integer] :unread number of unread messages
|
26
|
+
# @option args [Integer] :total total number of messages
|
27
|
+
def initialize(args=nil)
|
28
|
+
Messages.supervise as: :messages, size: 1
|
29
|
+
messages = Actor[:messages]
|
30
|
+
@enabled = false
|
31
|
+
@ids = ThreadSafe::Array.new
|
32
|
+
unless args.nil?
|
33
|
+
@unread = args[:unread] unless args[:unread].nil?
|
34
|
+
@total = args[:total] unless args[:total].nil?
|
35
|
+
end
|
36
|
+
client = Actor[:client]
|
37
|
+
create_from_string(client.command('sms list'))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Text messages.
|
41
|
+
#
|
42
|
+
# @return [Sms::Messages]
|
43
|
+
def messages
|
44
|
+
Actor[:messages]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Number of read messages.
|
48
|
+
#
|
49
|
+
# @return [Integer] the number of read messages.
|
50
|
+
def read
|
51
|
+
(@total - @unread)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Assign number of read messages.
|
55
|
+
#
|
56
|
+
# @param [Integer] read Number of read messages.
|
57
|
+
def read=(read=nil)
|
58
|
+
@unread = (@total - read) unless read.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create a new {Sms} object from a +String+ with data fetched from the
|
62
|
+
# router.
|
63
|
+
#
|
64
|
+
# @param [String] data_string String with text message data from the
|
65
|
+
# router.
|
66
|
+
def create_from_string(data_string=nil)
|
67
|
+
data_array = data_string.split("\n")
|
68
|
+
data_array.each do |data_entry|
|
69
|
+
entry_array = data_entry.split(':')
|
70
|
+
if entry_array.length == 2
|
71
|
+
key = entry_array[0].downcase
|
72
|
+
val = entry_array[1]
|
73
|
+
if key.downcase.tr(' ', '_') == 'stored_ids'
|
74
|
+
idlist = val.split(' ')
|
75
|
+
idlist.each do |id|
|
76
|
+
@ids << id
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@ids.map! { |id| id.to_i }.sort!
|
82
|
+
end
|
83
|
+
|
84
|
+
# Load text messages.
|
85
|
+
def load_messages
|
86
|
+
client = Actor[:client]
|
87
|
+
messages = Actor[:messages]
|
88
|
+
client.connect unless client.connected?
|
89
|
+
client.authenticate unless client.authenticated?
|
90
|
+
@ids.each do |id|
|
91
|
+
messages.add_message Message.from_string(client.command("sms recvtxt #{id}"))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Dovado
|
4
|
+
class Router
|
5
|
+
class Sms
|
6
|
+
# A text message (SMS).
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
class Message
|
10
|
+
include Celluloid
|
11
|
+
|
12
|
+
# Message Id.
|
13
|
+
# @return [String,Integer,Symbol]
|
14
|
+
attr_reader :id
|
15
|
+
# Message body.
|
16
|
+
# @return [String]
|
17
|
+
attr_reader :body
|
18
|
+
# Message PDU's.
|
19
|
+
# @return [Array]
|
20
|
+
attr_reader :pdus
|
21
|
+
# Message sender.
|
22
|
+
# @return [String]
|
23
|
+
attr_reader :from
|
24
|
+
# Message send timestamp.
|
25
|
+
# @return [DateTime]
|
26
|
+
attr_reader :sent
|
27
|
+
# Message text encoding.
|
28
|
+
# @return [Encoding]
|
29
|
+
attr_reader :encoding
|
30
|
+
|
31
|
+
# Create a new {Message} object.
|
32
|
+
#
|
33
|
+
# @param [Hash] args arguments.
|
34
|
+
# @option args [Integer,String,Symbol] :id Message Id.
|
35
|
+
# @option args [String] :body Message body.
|
36
|
+
# @option args [Array] :pdus Message PDU's.
|
37
|
+
# @option args [String] :from Message sender.
|
38
|
+
# @option args [DateTime] :sent Message send timestamp.
|
39
|
+
# @option args [Encoding] :encoding Message text encoding.
|
40
|
+
def initialize(args=nil)
|
41
|
+
unless args.nil?
|
42
|
+
@id = args[:id] unless args[:id].nil?
|
43
|
+
@body = args[:body] unless args[:body].nil?
|
44
|
+
@pdus = args[:pdus] unless args[:pdus].nil?
|
45
|
+
@from = args[:from] unless args[:from].nil?
|
46
|
+
@sent = args[:sent] unless args[:sent].nil?
|
47
|
+
@encoding = args[:encoding] unless args[:encoding].nil?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create a new {Message} object from a +String+.
|
52
|
+
#
|
53
|
+
# @param [String] string message data to create object from.
|
54
|
+
# @return [Message] a new {Message} object.
|
55
|
+
def self.from_string(string=nil)
|
56
|
+
hash = ThreadSafe::Cache.new
|
57
|
+
message_body = ""
|
58
|
+
array = string.split("\n")
|
59
|
+
array.each do |row|
|
60
|
+
row_array = row.split(':')
|
61
|
+
if row_array.length == 2
|
62
|
+
key = row_array[0].downcase
|
63
|
+
val = row_array[1]
|
64
|
+
case key.strip
|
65
|
+
when 'from'
|
66
|
+
hash[:from] = val.strip
|
67
|
+
when 'alphabet'
|
68
|
+
begin
|
69
|
+
hash[:encoding] = Encoding.find(val.strip)
|
70
|
+
rescue ArgumentError
|
71
|
+
hash[:encoding] = Encoding::UTF_8
|
72
|
+
end
|
73
|
+
when 'id'
|
74
|
+
hash[:id] = val.strip.to_i
|
75
|
+
end
|
76
|
+
elsif row_array.length > 2
|
77
|
+
sent = row.match(/[Ss]ent\:\W(.*)/)
|
78
|
+
hash[:sent] = DateTime.parse(sent[1].strip)
|
79
|
+
else
|
80
|
+
unless row.downcase =~ /end of sms/
|
81
|
+
message_body += "#{row}\n"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
hash[:body] = message_body.tr(">>", "").tr("\x17", "").strip.force_encoding(hash[:encoding])
|
86
|
+
|
87
|
+
Message.new(hash)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'thread_safe'
|
2
|
+
|
3
|
+
module Dovado
|
4
|
+
class Router
|
5
|
+
class Sms
|
6
|
+
# Text messages.
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
class Messages
|
10
|
+
include Celluloid
|
11
|
+
|
12
|
+
# Create a new {Messages} object.
|
13
|
+
def initialize
|
14
|
+
@messages = ThreadSafe::Cache.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add a message to the local cache.
|
18
|
+
# @param [Message] message
|
19
|
+
def add_message(message)
|
20
|
+
@messages[message.id] = message unless message.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fetch a {Message} from the cache.
|
24
|
+
#
|
25
|
+
# @param [String,Integer,Symbol] id Id of the message.
|
26
|
+
# @return [Message] message object.
|
27
|
+
# @see {Message}
|
28
|
+
def get_message(id)
|
29
|
+
@messages[id] unless id.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def ids
|
33
|
+
@messages.keys
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Dovado
|
2
|
+
# Library utilities.
|
3
|
+
#
|
4
|
+
# @api private
|
5
|
+
# @since 1.0.0
|
6
|
+
class Utilities
|
7
|
+
include Celluloid
|
8
|
+
|
9
|
+
# Convert a key name to symbol.
|
10
|
+
#
|
11
|
+
# @param name [String] the key name to convert.
|
12
|
+
# @return [Symbol] the key name converted to a symbol.
|
13
|
+
def self.name_to_sym(name=nil)
|
14
|
+
name.downcase.tr(' ', '_').to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
# Build a sentence from an array.
|
18
|
+
#
|
19
|
+
# Ported from ActiveSupport:
|
20
|
+
# - File activesupport/lib/active_support/core_ext/array/conversions.rb, line 59
|
21
|
+
#
|
22
|
+
# @param [Array] ary the +Array+ to make a sentence of.
|
23
|
+
# @param [Hash] options optional settings.
|
24
|
+
# @option options [String] :words_connector
|
25
|
+
# @option options [String] :two_words_connector
|
26
|
+
# @option options [String] :last_word_connector
|
27
|
+
def self.array_to_sentence(ary, options = {:words_connector => ', ', :two_words_connector => ' and ', :last_word_connector => ' and '})
|
28
|
+
case ary.length
|
29
|
+
when 0
|
30
|
+
''
|
31
|
+
when 1
|
32
|
+
ary[0].to_s.dup
|
33
|
+
when 2
|
34
|
+
"#{ary[0]}#{options[:two_words_connector]}#{ary[1]}"
|
35
|
+
else
|
36
|
+
"#{ary[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{ary[-1]}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/ruby-dovado.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dovado/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ruby-dovado"
|
8
|
+
spec.version = Dovado::VERSION
|
9
|
+
spec.authors = ["Jan Lindblom"]
|
10
|
+
spec.email = ["janlindblom@fastmail.fm"]
|
11
|
+
|
12
|
+
spec.summary = %q{Dovado Router API for Ruby.}
|
13
|
+
spec.homepage = "https://bitbucket.org/janlindblom/ruby-dovado"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "celluloid", "~> 0.17"
|
22
|
+
spec.add_runtime_dependency "thread_safe", "~> 0.3"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
26
|
+
spec.add_development_dependency "yard", "~> 0.8"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.3"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-dovado
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Lindblom
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: celluloid
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.17'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.17'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thread_safe
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.3'
|
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.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.3'
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- janlindblom@fastmail.fm
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".document"
|
119
|
+
- ".gitignore"
|
120
|
+
- ".rspec"
|
121
|
+
- ".ruby-version"
|
122
|
+
- ".travis.yml"
|
123
|
+
- CODE_OF_CONDUCT.md
|
124
|
+
- Gemfile
|
125
|
+
- LICENSE.txt
|
126
|
+
- README.md
|
127
|
+
- Rakefile
|
128
|
+
- VERSION
|
129
|
+
- lib/dovado.rb
|
130
|
+
- lib/dovado/client.rb
|
131
|
+
- lib/dovado/connection_error.rb
|
132
|
+
- lib/dovado/router.rb
|
133
|
+
- lib/dovado/router/info.rb
|
134
|
+
- lib/dovado/router/info/operator.rb
|
135
|
+
- lib/dovado/router/info/operator/telia.rb
|
136
|
+
- lib/dovado/router/services.rb
|
137
|
+
- lib/dovado/router/sms.rb
|
138
|
+
- lib/dovado/router/sms/message.rb
|
139
|
+
- lib/dovado/router/sms/messages.rb
|
140
|
+
- lib/dovado/utilities.rb
|
141
|
+
- lib/dovado/version.rb
|
142
|
+
- ruby-dovado.gemspec
|
143
|
+
homepage: https://bitbucket.org/janlindblom/ruby-dovado
|
144
|
+
licenses:
|
145
|
+
- MIT
|
146
|
+
metadata: {}
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubyforge_project:
|
163
|
+
rubygems_version: 2.4.5
|
164
|
+
signing_key:
|
165
|
+
specification_version: 4
|
166
|
+
summary: Dovado Router API for Ruby.
|
167
|
+
test_files: []
|
168
|
+
has_rdoc:
|