simperium 0.0.2.1 → 0.0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/README.md +2 -0
- data/VERSION +1 -0
- data/lib/simperium/changes.rb +16 -0
- data/lib/simperium/error_handling.rb +19 -0
- data/lib/simperium/heroku-addon-doc.md +153 -0
- data/lib/simperium/listener-export-mongohq +48 -0
- data/lib/simperium/version.rb +1 -1
- data/simperium.gemspec +22 -0
- data/test/test_simperium.rb +88 -0
- data/test/test_simperium_mirror.rb +12 -0
- metadata +13 -3
data/Gemfile
ADDED
data/README.md
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.2.2
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Simperium
|
2
|
+
class ChangeProcessor
|
3
|
+
def process(change)
|
4
|
+
if change['o'] == 'M'
|
5
|
+
if change.include?('sv')
|
6
|
+
change['v'].each do |key|
|
7
|
+
handler = self.send('on_change_#{key}')
|
8
|
+
if handler
|
9
|
+
handler(change['d'][key])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ErrorHandling
|
2
|
+
def self.handle_restclient_error(e)
|
3
|
+
case e
|
4
|
+
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
5
|
+
message = "Could not connect to Simperium (auth.simperium.com). Please check your internet connection and try again. If the problem continues, you should check Simperium's service status at https://simperium.com/, or let us know at contact@simperium.com."
|
6
|
+
when SocketError
|
7
|
+
message = "Unexpected error when trying to connect to Simpierum. HINT: You may be seeing this message because your DNS is not working. To check, try running 'host simperium.com' from the command line."
|
8
|
+
else
|
9
|
+
message = "Unexpected error communicating with Simperium. If this problem persists, let us know at contact@simperium.com."
|
10
|
+
end
|
11
|
+
message += "\n\n(Network error: #{e.message})"
|
12
|
+
raise StandardError.new(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.handle_api_error(rcode, rbody)
|
16
|
+
message = rcode.to_s + ' '+ rbody
|
17
|
+
raise StandardError.new(message)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
Simperium(http://addons.heroku.com/simperium) is an [add-on](http://addons.heroku.com) for circulating your data between mobile, web, and desktop versions of your app.
|
2
|
+
|
3
|
+
Adding Simpierum to your app makes your code simpler and your users happier:
|
4
|
+
|
5
|
+
* Data transparently moves across mobile, web, and desktop versions of your app
|
6
|
+
* Your users can read and write data even when they're offline
|
7
|
+
* Multiple users can collaborate with the same data at the same time
|
8
|
+
* You can build unique backend services that read and write data
|
9
|
+
|
10
|
+
Simperium is accessible via an API and has supported backend libraries for Ruby and Python and client libraries for Javascript and iOS/OS X. This add-on lets you mirror data circulated by Simpierum directly into your datastore.
|
11
|
+
|
12
|
+
## Provisioning the add-on
|
13
|
+
|
14
|
+
Simperium can be attached to a Heroku application via the CLI:
|
15
|
+
|
16
|
+
<div class="callout" markdown="1">
|
17
|
+
A list of all plans available can be found [here](http://addons.heroku.com/simperium).
|
18
|
+
</div>
|
19
|
+
|
20
|
+
:::term
|
21
|
+
$ heroku addons:add simperium
|
22
|
+
-----> Adding simperium to sharp-mountain-4005... done, v18 (free)
|
23
|
+
|
24
|
+
Once Simperium has been added a `SIMPERIUM_APP_ID` and `SIMPERIUM_ADMIN_KEY` setting will be available in the app configuration and will contain keys to access the newly provisioned Simperium app instance. This can be confirmed using the `heroku config` command.
|
25
|
+
|
26
|
+
:::term
|
27
|
+
$ heroku config | grep SIMPERIUM_APP_ID
|
28
|
+
SIMPERIUM_APP_ID => frogs-criteria-4c4
|
29
|
+
|
30
|
+
:::term
|
31
|
+
$ heroku config | grep SIMPERIUM_ADMIN_KEY
|
32
|
+
SIMPERIUM_ADMIN_KEY => cbbae31841ac4d44a93cd82081a5b74f
|
33
|
+
|
34
|
+
After installing Simpierum your application can begin mirroring data to your datastore.
|
35
|
+
|
36
|
+
## Local setup
|
37
|
+
|
38
|
+
### Environment setup
|
39
|
+
|
40
|
+
After provisioning the add-on you'll want to locally replicate the config vars so your development environment can operate against the service.
|
41
|
+
|
42
|
+
<div class="callout" markdown="1">
|
43
|
+
Though less portable it’s also possible to set local environment variables using `export SIMPERIUM_APP_ID=value` and `export SIMPERIUM_APP_KEY=value`.
|
44
|
+
</div>
|
45
|
+
|
46
|
+
Use [Foreman](config-vars#local_setup) to reliably configure and run the process formation specified in your app’s [Procfile](procfile). Foreman reads configuration variables from an .env file. Use the following command to add the SIMPERIUM_APP_ID and SIMPERIUM_ADMIN_KEY values retrieved from heroku config to `.env`.
|
47
|
+
|
48
|
+
:::term
|
49
|
+
$ heroku config -s | grep SIMPERIUM_APP_ID >> .env
|
50
|
+
$ heroku config -s | grep SIMPERIUM_ADMIN_KEY >> .env
|
51
|
+
$ more .env
|
52
|
+
|
53
|
+
<p class="warning" markdown="1">
|
54
|
+
Credentials and other sensitive configuration values should not be committed to source-control. In Git exclude the .env file with: `echo .env >> .gitignore`.
|
55
|
+
</p>
|
56
|
+
|
57
|
+
### Mirroring Data from Simperium to MongoHQ
|
58
|
+
|
59
|
+
In order to begin mirroring data from Simperium to MongoHQ, we need to install the simperium gem.
|
60
|
+
|
61
|
+
:::term
|
62
|
+
sudo gem install simperium
|
63
|
+
|
64
|
+
Grab a copy of the listner file that handles mirroring between MongoHQ and Simperium:
|
65
|
+
|
66
|
+
:::term
|
67
|
+
$ curl -O https://raw.github.com/Simperium/simperium/master/ruby/lib/simperium/listener-export-mongohq.rb
|
68
|
+
|
69
|
+
Install the mongo gem:
|
70
|
+
|
71
|
+
:::term
|
72
|
+
$ sudo gem update --system
|
73
|
+
|
74
|
+
:::term
|
75
|
+
sudo gem install mongo
|
76
|
+
sudo gem install bson_ext
|
77
|
+
|
78
|
+
Now, let Heroku know we want to run this new listener:
|
79
|
+
|
80
|
+
:::term
|
81
|
+
$ echo "worker: ruby listener-export-mongohq SIMPERIUM_APP_ID SIMPERIUM_ADMIN_KEY BUCKET_NAME" > Procfile
|
82
|
+
|
83
|
+
Note, BUCKET_NAME is the name of the bucket you want to mirror.
|
84
|
+
|
85
|
+
Start up our mongo instance with MongoHQ:
|
86
|
+
|
87
|
+
:::term
|
88
|
+
heroku addons:add mongohq:free
|
89
|
+
|
90
|
+
Finally, commit and re-push to Heroku:
|
91
|
+
|
92
|
+
:::term
|
93
|
+
$ git add .
|
94
|
+
$ git commit -m "realtime export to MongoHQ"
|
95
|
+
$ git push heroku master
|
96
|
+
|
97
|
+
Simperium activity can be observed within the Heroku log-stream by running the following:
|
98
|
+
|
99
|
+
:::term
|
100
|
+
$ heroku logs --tail
|
101
|
+
|
102
|
+
## Dashboard
|
103
|
+
|
104
|
+
<div class="callout" markdown="1">
|
105
|
+
For more information on the features available within the Simperium dashboard please see the docs at [simperium.com/docs/reference](http://simperium.com/docs/reference).
|
106
|
+
</div>
|
107
|
+
|
108
|
+
The Simpierum dashboard allows you to delete app data, debug with our data browser, and invite developers to your Simperium app.
|
109
|
+
|
110
|
+
![Simperium Dashboard](http://i.imgur.com/FkuUw.png "Simpierum Dashboard")
|
111
|
+
|
112
|
+
The dashboard can be accessed via the CLI:
|
113
|
+
|
114
|
+
:::term
|
115
|
+
$ heroku addons:open simperium
|
116
|
+
Opening simpierum for sharp-mountain-4005…
|
117
|
+
|
118
|
+
or by visiting the [Heroku apps web interface](http://heroku.com/myapps) and selecting the application in question. Select Simperium from the Add-ons menu.
|
119
|
+
|
120
|
+
![Simperium Add-ons Dropdown](http://f.cl.ly/items/1B090n1P0d3W0I0R172r/addons.png "Simperium Add-ons Dropdown")
|
121
|
+
|
122
|
+
|
123
|
+
## Migrating between plans
|
124
|
+
|
125
|
+
<div class="note" markdown="1">Application owners should carefully manage the migration timing to ensure proper application function during the migration process.</div>
|
126
|
+
|
127
|
+
Use the `heroku addons:upgrade` command to migrate to a new plan.
|
128
|
+
|
129
|
+
:::term
|
130
|
+
$ heroku addons:upgrade simperium:pro
|
131
|
+
-----> Upgrading simperium:pro to sharp-mountain-4005... done, v18 ($XX/mo)
|
132
|
+
Your plan has been updated to: simperium:pro
|
133
|
+
|
134
|
+
## Removing the add-on
|
135
|
+
|
136
|
+
Simperium can be removed via the CLI.
|
137
|
+
|
138
|
+
<div class="warning" markdown="1">This will destroy all associated data and cannot be undone!</div>
|
139
|
+
|
140
|
+
:::term
|
141
|
+
$ heroku addons:remove simperium
|
142
|
+
-----> Removing simperium from sharp-mountain-4005... done, v20 (free)
|
143
|
+
|
144
|
+
## Support
|
145
|
+
|
146
|
+
All Simperium support and runtime issues should be logged with Heroku Support at https://support.heroku.com. Any non-support related issues or product feedback is welcome at help@simperium.com.
|
147
|
+
|
148
|
+
## Additional resources
|
149
|
+
|
150
|
+
Additional resources are available at:
|
151
|
+
|
152
|
+
* [Site docs](http://simperium.com/docs/reference)
|
153
|
+
* [Some screencast](https://simperium.com)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'simperium'
|
4
|
+
require 'uri'
|
5
|
+
require 'mongo'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
MONGOHQ_URL = ENV['MONGOHQ_URL']
|
9
|
+
|
10
|
+
uri = URI.parse(MONGOHQ_URL)
|
11
|
+
conn = Mongo::Connection.from_uri(MONGOHQ_URL)
|
12
|
+
$db = conn.db(uri.path.gsub(/^\//, ''))
|
13
|
+
|
14
|
+
def main(appname, admin_key, bucket)
|
15
|
+
_bucket = Bucket.new(appname, admin_key, bucket)
|
16
|
+
|
17
|
+
begin
|
18
|
+
cv = $db['__meta__'].find_one
|
19
|
+
cv = cv['cv']
|
20
|
+
rescue StandardError => e
|
21
|
+
cv = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
while true do
|
26
|
+
changes = _bucket.all(:cv => cv, :data=>true)
|
27
|
+
for change in changes
|
28
|
+
data = change['d']
|
29
|
+
# update mongo with the latest version of the data
|
30
|
+
if data
|
31
|
+
data['_id'] = change['id']
|
32
|
+
# puts data
|
33
|
+
$db[bucket].save(data)
|
34
|
+
else
|
35
|
+
$db[bucket].remove({'_id' => change['id']})
|
36
|
+
end
|
37
|
+
# persist the cv to mongo, so changes don't need to be
|
38
|
+
# re-processed after restart
|
39
|
+
$db['__meta__'].save({'_id' => 'cv', 'cv' => change['cv']})
|
40
|
+
cv = change['cv']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
rescue StandardError => e
|
44
|
+
raise StandardError.new('Mirroring failed')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
main(ARGV[0], ARGV[1], ARGV[2])
|
data/lib/simperium/version.rb
CHANGED
data/simperium.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
2
|
+
|
3
|
+
require 'simperium/version'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = 'simperium'
|
7
|
+
s.version = Simperium::VERSION
|
8
|
+
s.summary = 'Ruby bindings for the Simperium API'
|
9
|
+
s.description = 'Simperium moves data instantly and automatically everywhere it\'s needed. See https://simperium.com for details.'
|
10
|
+
s.authors = ['Ray Ventura']
|
11
|
+
s.email = ['ray@simperium.com']
|
12
|
+
s.homepage = 'https://simperium.com/docs/reference'
|
13
|
+
s.require_paths = %w{lib}
|
14
|
+
|
15
|
+
s.add_dependency('rest-client', '~> 1.4')
|
16
|
+
s.add_dependency('uuid')
|
17
|
+
s.add_dependency('json')
|
18
|
+
s.add_dependency('mongo')
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.require_paths = ['lib']
|
22
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'uuid'
|
4
|
+
require 'simperium'
|
5
|
+
|
6
|
+
@@api_key = ENV['SIMPERIUM_CLIENT_TEST_APIKEY']
|
7
|
+
@@appname = ENV['SIMPERIUM_CLIENT_TEST_APPNAME']
|
8
|
+
|
9
|
+
# cache user create to cut down on the number of users created by the test suite
|
10
|
+
@@_auth_token = nil
|
11
|
+
def get_auth_token
|
12
|
+
if @@_auth_token.nil?
|
13
|
+
auth = Simperium::Auth.new(@@appname, @@api_key)
|
14
|
+
uuid = UUID.new
|
15
|
+
username = uuid.generate(:compact) + '@foo.com'
|
16
|
+
password = uuid.generate(:compact)
|
17
|
+
@@_auth_token = auth.create(username, password)
|
18
|
+
end
|
19
|
+
return @@_auth_token
|
20
|
+
end
|
21
|
+
|
22
|
+
class TestSimperiumRuby < Test::Unit::TestCase
|
23
|
+
def test_auth_create
|
24
|
+
get_auth_token
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_bucket_get
|
28
|
+
uuid = UUID.new
|
29
|
+
bucket = Simperium::Bucket.new(@@appname, get_auth_token, uuid.generate(:compact))
|
30
|
+
bucket.post('item1', {'x'=> 1})
|
31
|
+
assert_equal(bucket.get('item1'), {'x' => 1})
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_bucket_index
|
35
|
+
uuid = UUID.new
|
36
|
+
bucket = Simperium::Bucket.new(@@appname, get_auth_token, uuid.generate(:compact))
|
37
|
+
(0..2).each { |i| bucket.post("item#{i}", {'x' => i}) }
|
38
|
+
|
39
|
+
got = bucket.index(:data=>false, :mark=>nil, :limit=>2, :since=>nil)
|
40
|
+
want = {
|
41
|
+
'current' => got['current'],
|
42
|
+
'mark' => got['mark'],
|
43
|
+
'index' => [
|
44
|
+
{'id' => 'item2', 'v' => 1},
|
45
|
+
{'id' => 'item1', 'v' => 1}] }
|
46
|
+
assert_equal(want, got)
|
47
|
+
|
48
|
+
got2 = bucket.index(:data=>false, :mark=>got['mark'], :limit=>2, :since=>nil)
|
49
|
+
want2 = {
|
50
|
+
'current'=> got['current'],
|
51
|
+
'index' => [
|
52
|
+
{'id' => 'item0', 'v' => 1}] }
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_bucket_post
|
56
|
+
uuid = UUID.new
|
57
|
+
bucket = Simperium::Bucket.new(@@appname, get_auth_token, uuid.generate(:compact))
|
58
|
+
bucket.post('item1', {'a'=>1})
|
59
|
+
assert_equal(bucket.get('item1'), {'a'=>1})
|
60
|
+
|
61
|
+
bucket.post('item1', {'b'=>2})
|
62
|
+
assert_equal(bucket.get('item1'), {'a'=>1, 'b'=>2})
|
63
|
+
|
64
|
+
bucket.post('item1', {'c'=>3}, :replace=>true)
|
65
|
+
assert_equal(bucket.get('item1'), {'c'=>3})
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_user_get
|
69
|
+
user = Simperium::User.new(@@appname, get_auth_token)
|
70
|
+
user.post({'x'=> 1})
|
71
|
+
assert_equal(user.get, {'x'=> 1})
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_api_getitem
|
75
|
+
api = Simperium::Api.new(@@appname, get_auth_token)
|
76
|
+
assert_instance_of(Simperium::Bucket, api['bucket'], "api[bucket] should be an instance of Bucket")
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_api_getattr
|
80
|
+
api = Simperium::Api.new(@@appname, get_auth_token)
|
81
|
+
assert_instance_of(Simperium::Bucket, api.bucket, "api.bucket should be an instance of Bucket")
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_api_user
|
85
|
+
api = Simperium::Api.new(@@appname, get_auth_token)
|
86
|
+
assert_instance_of(Simperium::User, api.user, "api.user should be an instance of User")
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'simperium/listener-export-mongohq'
|
3
|
+
|
4
|
+
@admin_key = ENV['SIMPERIUM_CLIENT_TEST_ADMINKEY']
|
5
|
+
@appname = ENV['SIMPERIUM_CLIENT_TEST_APPNAME']
|
6
|
+
@bucket = 'todo'
|
7
|
+
|
8
|
+
class TestMirror < Test::Unit::TestCase
|
9
|
+
def test_simperium_mirror
|
10
|
+
main(@admin_key, @appname, @bucket)
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simperium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 67
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
9
|
- 2
|
10
|
-
-
|
11
|
-
version: 0.0.2.
|
10
|
+
- 2
|
11
|
+
version: 0.0.2.2
|
12
12
|
platform: ruby
|
13
13
|
authors:
|
14
14
|
- Ray Ventura
|
@@ -85,8 +85,18 @@ extensions: []
|
|
85
85
|
extra_rdoc_files: []
|
86
86
|
|
87
87
|
files:
|
88
|
+
- Gemfile
|
89
|
+
- README.md
|
90
|
+
- VERSION
|
88
91
|
- lib/simperium.rb
|
92
|
+
- lib/simperium/changes.rb
|
93
|
+
- lib/simperium/error_handling.rb
|
94
|
+
- lib/simperium/heroku-addon-doc.md
|
95
|
+
- lib/simperium/listener-export-mongohq
|
89
96
|
- lib/simperium/version.rb
|
97
|
+
- simperium.gemspec
|
98
|
+
- test/test_simperium.rb
|
99
|
+
- test/test_simperium_mirror.rb
|
90
100
|
homepage: https://simperium.com/docs/reference
|
91
101
|
licenses: []
|
92
102
|
|