rhosync 2.0.0.beta2 → 2.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -1
- data/Rakefile +2 -2
- data/doc/protocol.html +83 -83
- data/generators/rhosync.rb +11 -1
- data/generators/templates/application/spec/spec_helper.rb +27 -0
- data/generators/templates/source/source_adapter.rb +1 -1
- data/generators/templates/source/source_spec.rb +25 -0
- data/lib/rhosync/app.rb +1 -3
- data/lib/rhosync/bulk_data/bulk_data.rb +1 -1
- data/lib/rhosync/bulk_data/syncdb.schema +8 -5
- data/lib/rhosync/client_sync.rb +5 -4
- data/lib/rhosync/jobs/bulk_data_job.rb +18 -4
- data/lib/rhosync/server.rb +10 -4
- data/lib/rhosync/source_adapter.rb +23 -19
- data/lib/rhosync/source_sync.rb +1 -2
- data/lib/rhosync/store.rb +5 -2
- data/lib/rhosync/tasks.rb +45 -18
- data/lib/rhosync/test_methods.rb +72 -0
- data/lib/rhosync/version.rb +1 -1
- data/lib/rhosync.rb +15 -6
- data/spec/apps/rhotestapp/application.rb +3 -1
- data/spec/apps/rhotestapp/settings/settings.yml +3 -0
- data/spec/apps/rhotestapp/sources/sample_adapter.rb +8 -3
- data/spec/client_sync_spec.rb +16 -4
- data/spec/generator/generator_spec.rb +11 -7
- data/spec/jobs/bulk_data_job_spec.rb +24 -0
- data/spec/rhosync_spec.rb +1 -0
- data/spec/server/server_spec.rb +23 -4
- data/spec/source_adapter_spec.rb +14 -14
- data/spec/source_sync_spec.rb +9 -0
- data/spec/spec_helper.rb +107 -86
- data/spec/store_spec.rb +11 -0
- data/spec/test_methods_spec.rb +89 -0
- metadata +13 -8
data/generators/rhosync.rb
CHANGED
@@ -59,6 +59,11 @@ module Rhosync
|
|
59
59
|
template.source = 'Rakefile'
|
60
60
|
template.destination = "#{name}/Rakefile"
|
61
61
|
end
|
62
|
+
|
63
|
+
template :spec_helper do |template|
|
64
|
+
template.source = 'spec/spec_helper.rb'
|
65
|
+
template.destination = "#{name}/spec/spec_helper.rb"
|
66
|
+
end
|
62
67
|
end
|
63
68
|
|
64
69
|
class SourceGenerator < BaseGenerator
|
@@ -78,7 +83,7 @@ module Rhosync
|
|
78
83
|
template :source do |template|
|
79
84
|
template.source = 'source_adapter.rb'
|
80
85
|
template.destination = "sources/#{underscore_name}.rb"
|
81
|
-
settings_file = 'settings
|
86
|
+
settings_file = File.join(@destination_root,'settings','settings.yml')
|
82
87
|
settings = YAML.load_file(settings_file)
|
83
88
|
settings[:sources] ||= {}
|
84
89
|
settings[:sources][class_name] = {:poll_interval => 300}
|
@@ -91,6 +96,11 @@ module Rhosync
|
|
91
96
|
file.write envs.to_yaml[3..-1]
|
92
97
|
end
|
93
98
|
end
|
99
|
+
|
100
|
+
template :source_spec do |template|
|
101
|
+
template.source = 'source_spec.rb'
|
102
|
+
template.destination = "spec/sources/#{underscore_name}_spec.rb"
|
103
|
+
end
|
94
104
|
end
|
95
105
|
|
96
106
|
add :app, AppGenerator
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
# Set environment to test
|
4
|
+
ENV['RHO_ENV'] = 'test'
|
5
|
+
ROOT_PATH = ENV['ROOT_PATH']
|
6
|
+
|
7
|
+
# Try to load vendor-ed rhosync, otherwise load the gem
|
8
|
+
begin
|
9
|
+
require 'vendor/rhosync/lib/rhosync'
|
10
|
+
rescue LoadError
|
11
|
+
require 'rhosync'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Load our rhosync application
|
15
|
+
require 'application'
|
16
|
+
include Rhosync
|
17
|
+
|
18
|
+
require 'rhosync/test_methods'
|
19
|
+
|
20
|
+
describe "SpecHelper", :shared => true do
|
21
|
+
include Rhosync::TestMethods
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
Store.db.flushdb
|
25
|
+
Application.initializer(ROOT_PATH)
|
26
|
+
end
|
27
|
+
end
|
@@ -7,7 +7,7 @@ class <%=class_name%> < SourceAdapter
|
|
7
7
|
# TODO: Login to your data source here if necessary
|
8
8
|
end
|
9
9
|
|
10
|
-
def query
|
10
|
+
def query(params=nil)
|
11
11
|
# TODO: Query your backend data source and assign the records
|
12
12
|
# to a nested hash structure called @result. For example:
|
13
13
|
# @result = {
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
2
|
+
|
3
|
+
describe "<%=class_name%>" do
|
4
|
+
it_should_behave_like "SpecHelper"
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
setup_test_for <%=class_name%>,'testuser'
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should process <%=class_name%> query" do
|
11
|
+
pending
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should process <%=class_name%> create" do
|
15
|
+
pending
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should process <%=class_name%> update" do
|
19
|
+
pending
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should process <%=class_name%> delete" do
|
23
|
+
pending
|
24
|
+
end
|
25
|
+
end
|
data/lib/rhosync/app.rb
CHANGED
@@ -50,16 +50,14 @@ module Rhosync
|
|
50
50
|
|
51
51
|
def partition_sources(partition,user_id)
|
52
52
|
names = []
|
53
|
-
need_refresh = false
|
54
53
|
sources.members.each do |source|
|
55
54
|
s = Source.load(source,{:app_id => self.name,
|
56
55
|
:user_id => user_id})
|
57
56
|
if s.partition == partition
|
58
57
|
names << s.name
|
59
|
-
need_refresh = true if !need_refresh and s.check_refresh_time
|
60
58
|
end
|
61
59
|
end
|
62
|
-
|
60
|
+
names
|
63
61
|
end
|
64
62
|
|
65
63
|
def store_blob(obj,field_name,blob)
|
@@ -5,14 +5,12 @@ CREATE TABLE client_info (
|
|
5
5
|
token_sent BIGINT default 0,
|
6
6
|
reset BIGINT default 0,
|
7
7
|
port VARCHAR(10) default NULL,
|
8
|
-
bulksync_state BIGINT default 0,
|
9
8
|
last_sync_success VARCHAR(100) default NULL);
|
10
9
|
CREATE TABLE object_values (
|
11
10
|
source_id BIGINT default NULL,
|
12
11
|
attrib varchar(255) default NULL,
|
13
12
|
object varchar(255) default NULL,
|
14
|
-
value varchar default NULL
|
15
|
-
attrib_type varchar(255) default NULL);
|
13
|
+
value varchar default NULL);
|
16
14
|
CREATE TABLE changed_values (
|
17
15
|
source_id BIGINT default NULL,
|
18
16
|
attrib varchar(255) default NULL,
|
@@ -25,13 +23,18 @@ CREATE TABLE sources (
|
|
25
23
|
source_id BIGINT PRIMARY KEY,
|
26
24
|
name VARCHAR(255) default NULL,
|
27
25
|
token BIGINT default NULL,
|
28
|
-
|
26
|
+
sync_priority BIGINT,
|
29
27
|
partition VARCHAR(255),
|
30
28
|
sync_type VARCHAR(255),
|
29
|
+
metadata varchar default NULL,
|
31
30
|
last_updated BIGINT default 0,
|
32
31
|
last_inserted_size BIGINT default 0,
|
33
32
|
last_deleted_size BIGINT default 0,
|
34
33
|
last_sync_duration BIGINT default 0,
|
35
34
|
last_sync_success BIGINT default 0,
|
36
35
|
backend_refresh_time BIGINT default 0,
|
37
|
-
source_attribs varchar default NULL
|
36
|
+
source_attribs varchar default NULL,
|
37
|
+
schema varchar default NULL,
|
38
|
+
schema_version varchar default NULL,
|
39
|
+
associations varchar default NULL,
|
40
|
+
blob_attribs varchar default NULL);
|
data/lib/rhosync/client_sync.rb
CHANGED
@@ -173,17 +173,18 @@ module Rhosync
|
|
173
173
|
name = BulkData.get_name(partition,client)
|
174
174
|
data = BulkData.load(name)
|
175
175
|
sources = client.app.partition_sources(partition,client.user_id)
|
176
|
-
if (data.nil? or (data.completed? and
|
177
|
-
sources
|
176
|
+
if (data.nil? or (data.completed? and !File.exist?(data.dbfile)) or
|
177
|
+
(data.completed? and data.refresh_time <= Time.now.to_i)) and sources.length > 0
|
178
178
|
data.delete if data
|
179
179
|
data = BulkData.create(:name => name,
|
180
180
|
:app_id => client.app_id,
|
181
181
|
:user_id => client.user_id,
|
182
|
-
:sources => sources
|
182
|
+
:sources => sources,
|
183
|
+
:refresh_time => Time.now.to_i + Rhosync.bulk_sync_poll_interval)
|
183
184
|
BulkData.enqueue("data_name" => name)
|
184
185
|
end
|
185
186
|
if data and data.completed?
|
186
|
-
client.update_clientdoc(sources
|
187
|
+
client.update_clientdoc(sources)
|
187
188
|
{:result => :url, :url => data.url}
|
188
189
|
elsif data
|
189
190
|
{:result => :wait}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'sqlite3'
|
2
|
+
require 'zip/zip'
|
2
3
|
|
3
4
|
module Rhosync
|
4
5
|
module BulkDataJob
|
@@ -16,13 +17,17 @@ module Rhosync
|
|
16
17
|
create_sqlite_data_file(bulk_data,ts)
|
17
18
|
timer = lap_timer('create_sqlite_data_file',timer)
|
18
19
|
create_hsql_data_file(bulk_data,ts) if Rhosync.blackberry_bulk_sync
|
19
|
-
|
20
|
+
lap_timer('create_hsql_data_file',timer)
|
21
|
+
log "finished bulk data process"
|
20
22
|
bulk_data.state = :completed
|
23
|
+
bulk_data.refresh_time = Time.now.to_i + Rhosync.bulk_sync_poll_interval
|
21
24
|
else
|
22
25
|
raise Exception.new("No bulk data found for #{params["data_name"]}")
|
23
26
|
end
|
24
27
|
rescue Exception => e
|
25
28
|
bulk_data.delete if bulk_data
|
29
|
+
log "Bulk data job raised: #{e.message}"
|
30
|
+
log e.backtrace.join("\n")
|
26
31
|
raise e
|
27
32
|
end
|
28
33
|
end
|
@@ -55,12 +60,12 @@ module Rhosync
|
|
55
60
|
def self.populate_sources_table(db,sources_refs)
|
56
61
|
db.transaction do |database|
|
57
62
|
database.prepare("insert into sources
|
58
|
-
(source_id,name,
|
59
|
-
values (
|
63
|
+
(source_id,name,sync_priority,partition,sync_type,source_attribs,metadata)
|
64
|
+
values (?,?,?,?,?,?,?)") do |stmt|
|
60
65
|
sources_refs.each do |source_name,ref|
|
61
66
|
s = ref[:source]
|
62
67
|
stmt.execute(s.source_id,s.name,s.priority,s.partition_type,
|
63
|
-
s.sync_type,refs_to_s(ref[:refs]))
|
68
|
+
s.sync_type,refs_to_s(ref[:refs]),s.get_value(:metadata))
|
64
69
|
end
|
65
70
|
end
|
66
71
|
end
|
@@ -74,6 +79,7 @@ module Rhosync
|
|
74
79
|
db.execute_batch(File.open(schema,'r').read)
|
75
80
|
src_counter = 1
|
76
81
|
bulk_data.sources.members.sort.each do |source_name|
|
82
|
+
timer = start_timer("start importing sqlite data for #{source_name}")
|
77
83
|
source = Source.load(source_name,{:app_id => bulk_data.app_id,
|
78
84
|
:user_id => bulk_data.user_id})
|
79
85
|
source.source_id = src_counter
|
@@ -81,9 +87,11 @@ module Rhosync
|
|
81
87
|
source_attrib_refs = import_data_to_object_values(db,source)
|
82
88
|
sources_refs[source_name] =
|
83
89
|
{:source => source, :refs => source_attrib_refs}
|
90
|
+
lap_timer("finished importing sqlite data for #{source_name}",timer)
|
84
91
|
end
|
85
92
|
populate_sources_table(db,sources_refs)
|
86
93
|
db.execute_batch(File.open(index,'r').read)
|
94
|
+
compress("#{bulk_data.dbfile}.rzip",bulk_data.dbfile)
|
87
95
|
end
|
88
96
|
|
89
97
|
def self.create_hsql_data_file(bulk_data,ts)
|
@@ -100,5 +108,11 @@ module Rhosync
|
|
100
108
|
dbfile = File.join(Rhosync.data_directory,bulk_data_name+'_'+ts+'.data')
|
101
109
|
[schema,index,dbfile]
|
102
110
|
end
|
111
|
+
|
112
|
+
def self.compress(archive,file)
|
113
|
+
Zip::ZipFile.open(archive, 'w') do |zipfile|
|
114
|
+
zipfile.add(File.basename(file),file)
|
115
|
+
end
|
116
|
+
end
|
103
117
|
end
|
104
118
|
end
|
data/lib/rhosync/server.rb
CHANGED
@@ -44,7 +44,13 @@ module Rhosync
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def do_login
|
47
|
-
|
47
|
+
begin
|
48
|
+
login ? status(200) : status(401)
|
49
|
+
rescue LoginException => le
|
50
|
+
throw :halt, [401, le.message]
|
51
|
+
rescue Exception => e
|
52
|
+
throw :halt, [500, e.message]
|
53
|
+
end
|
48
54
|
end
|
49
55
|
|
50
56
|
def login_required
|
@@ -52,10 +58,10 @@ module Rhosync
|
|
52
58
|
end
|
53
59
|
|
54
60
|
def login
|
55
|
-
if
|
56
|
-
user = current_app.authenticate(params[:login], params[:password], session)
|
57
|
-
else
|
61
|
+
if params[:login] == 'admin'
|
58
62
|
user = User.authenticate(params[:login], params[:password])
|
63
|
+
elsif current_app and current_app.can_authenticate?
|
64
|
+
user = current_app.authenticate(params[:login], params[:password], session)
|
59
65
|
end
|
60
66
|
if user
|
61
67
|
session[:login] = user.login
|
@@ -40,21 +40,37 @@ module Rhosync
|
|
40
40
|
def search(params=nil); end
|
41
41
|
|
42
42
|
def sync
|
43
|
-
|
44
|
-
if @result.empty?
|
43
|
+
if @result and @result.empty?
|
45
44
|
@source.lock(:md) do |s|
|
46
45
|
s.flash_data(:md)
|
47
46
|
s.put_value(:md_size,0)
|
48
47
|
end
|
49
48
|
else
|
50
|
-
|
51
|
-
|
49
|
+
if @result
|
50
|
+
Store.put_data(@tmp_docname,@result)
|
51
|
+
@stash_size += @result.size
|
52
|
+
end
|
52
53
|
@source.lock(:md) do |s|
|
53
|
-
|
54
|
-
s.
|
54
|
+
s.flash_data(:md)
|
55
|
+
Store.rename(@tmp_docname,s.docname(:md))
|
56
|
+
s.put_value(:md_size,@stash_size)
|
55
57
|
end
|
56
58
|
end
|
57
59
|
end
|
60
|
+
|
61
|
+
def do_query(params=nil)
|
62
|
+
@tmp_docname = @source.docname(:md) + get_random_uuid
|
63
|
+
@stash_size = 0
|
64
|
+
params ? self.query(params) : self.query
|
65
|
+
self.sync
|
66
|
+
end
|
67
|
+
|
68
|
+
def stash_result
|
69
|
+
return if @result.nil?
|
70
|
+
Store.put_data(@tmp_docname,@result,true)
|
71
|
+
@stash_size += @result.size
|
72
|
+
@result = nil
|
73
|
+
end
|
58
74
|
|
59
75
|
def create(name_value_list); end
|
60
76
|
|
@@ -67,29 +83,17 @@ module Rhosync
|
|
67
83
|
def logoff; end
|
68
84
|
|
69
85
|
def save(docname)
|
70
|
-
return if
|
86
|
+
return if @result.nil?
|
71
87
|
if @result.empty?
|
72
88
|
Store.flash_data(docname)
|
73
89
|
else
|
74
90
|
Store.put_data(docname,@result)
|
75
91
|
end
|
76
92
|
end
|
77
|
-
|
78
|
-
# only implement this if you want RhoSync to install a callback into your backend
|
79
|
-
# def set_callback(notify_url)
|
80
|
-
# end
|
81
|
-
|
82
|
-
MSG_NIL_RESULT_ATTRIB = "You might have expected a synchronization but the @result attribute was 'nil'"
|
83
93
|
|
84
94
|
protected
|
85
95
|
def current_user
|
86
96
|
@source.user
|
87
97
|
end
|
88
|
-
|
89
|
-
private
|
90
|
-
def _result_nil? #:nodoc:
|
91
|
-
log MSG_NIL_RESULT_ATTRIB if @result.nil?
|
92
|
-
@result.nil?
|
93
|
-
end
|
94
98
|
end
|
95
99
|
end
|
data/lib/rhosync/source_sync.rb
CHANGED
@@ -225,8 +225,7 @@ module Rhosync
|
|
225
225
|
else
|
226
226
|
errordoc = @source.docname(:errors)
|
227
227
|
_get_metadata
|
228
|
-
|
229
|
-
@adapter.sync
|
228
|
+
@adapter.do_query(params)
|
230
229
|
end
|
231
230
|
# operation,sync succeeded, remove errors
|
232
231
|
Store.lock(errordoc) do
|
data/lib/rhosync/store.rb
CHANGED
@@ -12,7 +12,8 @@ module Rhosync
|
|
12
12
|
|
13
13
|
def create(server=nil)
|
14
14
|
@@db ||= _get_redis(server)
|
15
|
-
raise "Error connecting to Redis store." unless @@db and
|
15
|
+
raise "Error connecting to Redis store." unless @@db and
|
16
|
+
(@@db.is_a?(Redis) or @@db.is_a?(Redis::Client) or @@db.is_a?(Redis::Distributed))
|
16
17
|
end
|
17
18
|
|
18
19
|
# Adds set with given data, replaces existing set
|
@@ -53,7 +54,7 @@ module Rhosync
|
|
53
54
|
|
54
55
|
# Retrieves value for a given key
|
55
56
|
def get_value(dockey)
|
56
|
-
|
57
|
+
@@db.get(dockey) if dockey
|
57
58
|
end
|
58
59
|
|
59
60
|
# Retrieves set for given dockey,source,user
|
@@ -182,6 +183,8 @@ module Rhosync
|
|
182
183
|
host,port,db,password = server.split(':')
|
183
184
|
Redis.new(:thread_safe => true, :host => host,
|
184
185
|
:port => port, :db => db, :password => password)
|
186
|
+
elsif server and server.is_a?(Array)
|
187
|
+
Redis::Distributed.new :hosts => server
|
185
188
|
else
|
186
189
|
Redis.new(:thread_safe => true)
|
187
190
|
end
|
data/lib/rhosync/tasks.rb
CHANGED
@@ -102,13 +102,20 @@ namespace :rhosync do
|
|
102
102
|
task :create_user => :config do
|
103
103
|
login = ask "new user login: "
|
104
104
|
password = ask "new user password: "
|
105
|
-
RhosyncApi.create_user($url,$
|
105
|
+
RhosyncApi.create_user($url,$token,login,password)
|
106
106
|
end
|
107
107
|
|
108
|
-
desc "Deletes
|
108
|
+
desc "Deletes a user from rhosync"
|
109
109
|
task :delete_user => :config do
|
110
110
|
login = ask "user to delete: "
|
111
|
-
RhosyncApi.delete_user($url,$
|
111
|
+
RhosyncApi.delete_user($url,$token,login)
|
112
|
+
end
|
113
|
+
|
114
|
+
desc "Deletes a device from rhosync"
|
115
|
+
task :delete_device => :config do
|
116
|
+
user_id = ask "device's user_id: "
|
117
|
+
device_id = ask "device to delete: "
|
118
|
+
RhosyncApi.delete_client($url,$token,user_id,device_id)
|
112
119
|
end
|
113
120
|
|
114
121
|
# desc "Updates an existing user in rhosync"
|
@@ -120,22 +127,37 @@ namespace :rhosync do
|
|
120
127
|
# :login => login, :password => password, :attributes => {:new_password => new_password}})
|
121
128
|
# end
|
122
129
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
+
desc "Reset source refresh time"
|
131
|
+
task :reset_refresh => :config do
|
132
|
+
user = ask "user: "
|
133
|
+
source_name = ask "source name: "
|
134
|
+
RestClient.post("#{$url}/api/set_refresh_time", {:api_token => $token,
|
135
|
+
:user_name => user, :source_name => source_name})
|
136
|
+
end
|
130
137
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
138
|
+
begin
|
139
|
+
require 'spec/rake/spectask'
|
140
|
+
require 'rcov/rcovtask' unless windows?
|
141
|
+
|
142
|
+
desc "Run source adapter specs"
|
143
|
+
task :spec do
|
144
|
+
files = File.join('spec','sources','*_spec.rb')
|
145
|
+
Spec::Rake::SpecTask.new('rhosync:spec') do |t|
|
146
|
+
t.spec_files = FileList[files]
|
147
|
+
t.spec_opts = %w(-fn -b --color)
|
148
|
+
unless windows?
|
149
|
+
t.rcov = true
|
150
|
+
t.rcov_opts = ['--exclude', 'spec/*,gems/*']
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
rescue LoadError
|
155
|
+
if windows?
|
156
|
+
puts "rspec not available. Install it with: "
|
157
|
+
puts "gem install rspec\n\n"
|
158
|
+
else
|
159
|
+
puts "rspec / rcov not available. Install it with: "
|
160
|
+
puts "gem install rspec rcov\n\n"
|
139
161
|
end
|
140
162
|
end
|
141
163
|
|
@@ -160,6 +182,11 @@ namespace :rhosync do
|
|
160
182
|
task :attach => :dtach_installed do
|
161
183
|
sh "dtach -a #{rhosync_socket}" unless windows?
|
162
184
|
end
|
185
|
+
|
186
|
+
desc "Launch the web console in a browser - uses :syncserver: in settings.yml"
|
187
|
+
task :web => :config do
|
188
|
+
windows? ? sh("start #{$url}") : sh("open #{$url}")
|
189
|
+
end
|
163
190
|
end
|
164
191
|
|
165
192
|
load File.join(File.dirname(__FILE__),'..','..','tasks','redis.rake')
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Rhosync
|
2
|
+
class SourceAdapter
|
3
|
+
attr_accessor :result
|
4
|
+
end
|
5
|
+
|
6
|
+
module TestMethods
|
7
|
+
def setup_test_for(adapter,user_id)
|
8
|
+
app_id = 'application'
|
9
|
+
s_fields = {
|
10
|
+
:user_id => user_id,
|
11
|
+
:app_id => app_id
|
12
|
+
}
|
13
|
+
c_fields = {
|
14
|
+
:device_type => 'iPhone',
|
15
|
+
:device_pin => 'abcd',
|
16
|
+
:device_port => '3333',
|
17
|
+
:user_id => user_id,
|
18
|
+
:app_id => app_id
|
19
|
+
}
|
20
|
+
@u = User.create(:login => user_id)
|
21
|
+
@s = Source.load(adapter.to_s,s_fields)
|
22
|
+
@c = Client.create(c_fields,{:source_name => adapter.to_s})
|
23
|
+
@ss = SourceSync.new(@s)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_query
|
27
|
+
@ss.process_query
|
28
|
+
return md
|
29
|
+
end
|
30
|
+
|
31
|
+
def query_errors
|
32
|
+
@s.get_data(:errors)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_create(record)
|
36
|
+
@c.put_data(:create,{'temp-id' => record})
|
37
|
+
@ss.create(@c.id)
|
38
|
+
links = @c.get_data(:create_links)['temp-id']
|
39
|
+
links ? links['l'] : nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_errors
|
43
|
+
@c.get_data(:create_errors)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_update(record)
|
47
|
+
@c.put_data(:update,record)
|
48
|
+
@ss.update(@c.id)
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_errors
|
52
|
+
@c.get_data(:update_errors)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_delete(record)
|
56
|
+
@c.put_data(:delete,record)
|
57
|
+
@ss.delete(@c.id)
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_errors
|
61
|
+
@c.get_data(:delete_errors)
|
62
|
+
end
|
63
|
+
|
64
|
+
def md
|
65
|
+
@s.get_data(:md)
|
66
|
+
end
|
67
|
+
|
68
|
+
def cd
|
69
|
+
@c.get_data(:cd)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/rhosync/version.rb
CHANGED
data/lib/rhosync.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'redis'
|
2
|
+
require 'redis/distributed'
|
2
3
|
require 'json'
|
3
4
|
require 'base64'
|
4
5
|
require 'zip/zip'
|
@@ -29,12 +30,16 @@ module Rhosync
|
|
29
30
|
|
30
31
|
class InvalidArgumentError < RuntimeError; end
|
31
32
|
class RhosyncServerError < RuntimeError; end
|
33
|
+
|
34
|
+
# Used by application authenticate to indicate login failure
|
35
|
+
class LoginException < RuntimeError; end
|
36
|
+
|
32
37
|
extend self
|
33
38
|
|
34
39
|
class << self
|
35
40
|
attr_accessor :base_directory, :app_directory, :data_directory,
|
36
41
|
:vendor_directory, :blackberry_bulk_sync, :redis, :environment,
|
37
|
-
:log_disabled, :license
|
42
|
+
:log_disabled, :license, :bulk_sync_poll_interval
|
38
43
|
end
|
39
44
|
|
40
45
|
### Begin Rhosync setup methods
|
@@ -49,6 +54,7 @@ module Rhosync
|
|
49
54
|
Rhosync.data_directory = get_setting(config,environment,:data_directory)
|
50
55
|
Rhosync.vendor_directory = get_setting(config,environment,:vendor_directory)
|
51
56
|
Rhosync.blackberry_bulk_sync = get_setting(config,environment,:blackberry_bulk_sync,false)
|
57
|
+
Rhosync.bulk_sync_poll_interval = get_setting(config,environment,:bulk_sync_poll_interval,3600)
|
52
58
|
Rhosync.redis = get_setting(config,environment,:redis,false)
|
53
59
|
Rhosync.log_disabled = get_setting(config,environment,:log_disabled,false)
|
54
60
|
Rhosync.environment = environment
|
@@ -60,6 +66,7 @@ module Rhosync
|
|
60
66
|
Rhosync.data_directory ||= File.join(Rhosync.base_directory,'data')
|
61
67
|
Rhosync.vendor_directory ||= File.join(Rhosync.base_directory,'vendor')
|
62
68
|
Rhosync.blackberry_bulk_sync ||= false
|
69
|
+
Rhosync.bulk_sync_poll_interval ||= 3600
|
63
70
|
Rhosync.log_disabled ||= false
|
64
71
|
Rhosync.license = License.new
|
65
72
|
|
@@ -113,7 +120,7 @@ module Rhosync
|
|
113
120
|
def get_config(basedir)
|
114
121
|
# Load settings
|
115
122
|
settings_file = File.join(basedir,'settings','settings.yml') if basedir
|
116
|
-
|
123
|
+
YAML.load_file(settings_file) if settings_file and File.exist?(settings_file)
|
117
124
|
end
|
118
125
|
### End Rhosync setup methods
|
119
126
|
|
@@ -129,13 +136,15 @@ module Rhosync
|
|
129
136
|
|
130
137
|
# Serializes oav to set element
|
131
138
|
def setelement(obj,attrib,value)
|
132
|
-
"#{obj}:#{attrib}:#{Base64.encode64(value.to_s)}"
|
139
|
+
#"#{obj}:#{attrib}:#{Base64.encode64(value.to_s)}"
|
140
|
+
"#{obj}:#{attrib}:#{value.to_s}"
|
133
141
|
end
|
134
142
|
|
135
143
|
# De-serializes oav from set element
|
136
144
|
def getelement(element)
|
137
|
-
res = element.split(':')
|
138
|
-
[res[0], res[1], Base64.decode64(res[2].to_s)]
|
145
|
+
res = element.split(':',3)
|
146
|
+
#[res[0], res[1], Base64.decode64(res[2].to_s)]
|
147
|
+
[res[0], res[1], res[2]]
|
139
148
|
end
|
140
149
|
|
141
150
|
# Get random UUID string
|
@@ -224,7 +233,7 @@ module Rhosync
|
|
224
233
|
end
|
225
234
|
|
226
235
|
# Base rhosync application class
|
227
|
-
class Base
|
236
|
+
class Base
|
228
237
|
# Add everything in vendor to load path
|
229
238
|
# TODO: Integrate with 3rd party dependency management
|
230
239
|
def self.initializer(path=nil)
|
@@ -2,7 +2,9 @@ class Application < Rhosync::Base
|
|
2
2
|
class << self
|
3
3
|
def authenticate(username,password,session)
|
4
4
|
session[:auth] = "delegated"
|
5
|
-
|
5
|
+
raise RuntimeError.new('server error') if password == 'server error'
|
6
|
+
raise LoginException.new('login exception') if password == 'wrongpass'
|
7
|
+
password == 'wrongpassnomsg' ? false : true
|
6
8
|
end
|
7
9
|
|
8
10
|
# Add hooks for application startup here
|
@@ -11,13 +11,16 @@
|
|
11
11
|
:iphonepassphrase: certpassword
|
12
12
|
:iphoneserver: gateway.sandbox.push.apple.com
|
13
13
|
:iphoneport: 2195
|
14
|
+
:bulk_sync_poll_interval: 3600
|
14
15
|
:redis: localhost:6379
|
15
16
|
:syncserver: http://localhost:9292/application/
|
16
17
|
:test:
|
17
18
|
:licensefile: settings/license.key
|
19
|
+
:bulk_sync_poll_interval: 3600
|
18
20
|
:redis: localhost:6379
|
19
21
|
:syncserver: http://localhost:9292/application/
|
20
22
|
:production:
|
21
23
|
:licensefile: settings/license.key
|
24
|
+
:bulk_sync_poll_interval: 3600
|
22
25
|
:redis: localhost:6379
|
23
26
|
:syncserver: http://localhost:9292/application/
|