simperium 0.0.2.1 → 0.0.2.2
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.
- 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
|
+

|
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
|
+

|
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
|
|