rhoconnect 3.0.5 → 3.0.6
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/CHANGELOG.md +7 -1
- data/Gemfile.lock +9 -9
- data/README.md +4 -4
- data/Rakefile +41 -28
- data/bench/bench_runner.rb +4 -5
- data/bench/benchapp/Gemfile +1 -1
- data/bench/benchapp/Gemfile.lock +26 -27
- data/bench/benchapp/config.ru +4 -0
- data/bench/benchapp/log/passenger.3000.log +1 -0
- data/bench/benchapp/log/passenger.9292.log +59 -0
- data/bench/benchapp/settings/settings.yml +2 -0
- data/bench/benchapp/tmp/pids/passenger.3000.pid.lock +0 -0
- data/bench/benchapp/tmp/pids/passenger.9292.pid.lock +0 -0
- data/bench/distr_bench/distr_bench +7 -0
- data/bench/distr_bench/distr_bench_main +99 -0
- data/bench/distr_bench/run_distr_client.sh +12 -0
- data/bench/distr_bench/run_test_query_script.sh +50 -0
- data/bench/lib/bench/bench_result_processor.rb +90 -0
- data/bench/lib/bench/cli.rb +35 -2
- data/bench/lib/bench/logging.rb +2 -0
- data/bench/lib/bench/runner.rb +4 -2
- data/bench/lib/bench/session.rb +3 -1
- data/bench/lib/bench/statistics.rb +41 -1
- data/bench/lib/bench/timer.rb +7 -0
- data/bench/lib/bench/utils.rb +8 -0
- data/bench/lib/bench.rb +35 -9
- data/bench/lib/testdata/0-data.txt +0 -0
- data/bench/lib/testdata/1-data.txt +0 -0
- data/bench/lib/testdata/10-data.txt +15 -0
- data/bench/lib/testdata/2-data.txt +3 -0
- data/bench/lib/testdata/25-data.txt +39 -0
- data/bench/lib/testdata/250-data.txt +353 -0
- data/bench/lib/testdata/3-data.txt +4 -0
- data/bench/lib/testdata/5-data.txt +7 -8
- data/bench/lib/testdata/50-data.txt +70 -0
- data/bench/lib/testdata/500-data.txt +711 -0
- data/bench/prepare_bench +45 -0
- data/bench/run_bench.sh +3 -3
- data/bench/run_blob_script.sh +1 -1
- data/bench/run_cud_script.sh +1 -1
- data/bench/run_query_md_script.sh +1 -1
- data/bench/run_query_only_script.sh +1 -1
- data/bench/run_query_script.sh +1 -1
- data/bench/run_test_query_script.sh +30 -0
- data/bench/run_test_source_script.sh +21 -0
- data/bench/scripts/test_query_script.rb +64 -0
- data/bench/scripts/test_source_script.rb +27 -0
- data/bin/rhoconnect-benchmark +13 -0
- data/doc/client-objc.txt +236 -1
- data/doc/client.txt +132 -0
- data/doc/extending-rhoconnect-server.txt +79 -0
- data/doc/install.txt +1 -1
- data/doc/java-plugin.txt +291 -0
- data/doc/rest-api.txt +3 -1
- data/installer/unix-like/create_texts.rb +73 -16
- data/installer/unix-like/pre_install.sh +1 -1
- data/installer/unix-like/rho_connect_install_constants.rb +1 -1
- data/installer/utils/constants.rb +2 -2
- data/installer/utils/nix_install_test.rb +85 -75
- data/installer/utils/package_upload/repos.rake +82 -2
- data/installer/windows/rhosync.nsi +5 -5
- data/lib/rhoconnect/api/application/queue_updates.rb +14 -0
- data/lib/rhoconnect/api/source/set_db_doc.rb +3 -1
- data/lib/rhoconnect/server.rb +9 -17
- data/lib/rhoconnect/version.rb +1 -1
- data/rhoconnect.gemspec +1 -1
- data/spec/api/admin/get_api_token_spec.rb +6 -0
- data/spec/api/source/set_db_doc_spec.rb +13 -0
- data/spec/server/server_spec.rb +27 -1
- data/tasks/redis.rake +2 -2
- metadata +73 -48
- data/examples/simple/dump.rdb +0 -0
- data/installer/utils/package_upload/repos.rb +0 -83
data/bench/prepare_bench
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
|
|
5
|
+
require 'bench'
|
|
6
|
+
|
|
7
|
+
def create_subdir(dir)
|
|
8
|
+
begin
|
|
9
|
+
Dir.mkdir(dir)
|
|
10
|
+
rescue
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# 1) Extract Bench title
|
|
15
|
+
title = ARGV[0]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# 2) create result directory structure
|
|
19
|
+
['bench_results', ARGV[1]].each do |dir|
|
|
20
|
+
next if dir.nil?
|
|
21
|
+
create_subdir dir
|
|
22
|
+
Dir.chdir dir
|
|
23
|
+
end
|
|
24
|
+
result_dir = Dir.pwd
|
|
25
|
+
|
|
26
|
+
['raw_data', 'images'].each do |dir|
|
|
27
|
+
create_subdir dir
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# 3) create meta.yml file
|
|
31
|
+
meta_hash = {:x_keys => {}, :metrics => {}, :label => title}
|
|
32
|
+
x_keys = ARGV[2].split() if $ARGV[1]
|
|
33
|
+
x_keys ||= []
|
|
34
|
+
counter = 0
|
|
35
|
+
x_keys = x_keys.sort_by(&Bench.sort_natural_order)
|
|
36
|
+
x_keys.each do |x_key|
|
|
37
|
+
meta_hash[:x_keys][x_key] = counter
|
|
38
|
+
counter += 1
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
meta_hash[:metrics] = {'Throughput' => 0, 'Av.Time' => 1}
|
|
42
|
+
|
|
43
|
+
File.open(File.join(result_dir,'raw_data','meta.yml'), 'w') do |file|
|
|
44
|
+
file.write meta_hash.to_yaml unless meta_hash.empty?
|
|
45
|
+
end
|
data/bench/run_bench.sh
CHANGED
|
@@ -20,8 +20,8 @@ else
|
|
|
20
20
|
exit
|
|
21
21
|
fi
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
cd '../'
|
|
24
|
+
RHOCONNECT_HOME=`pwd`
|
|
25
25
|
|
|
26
26
|
echo "Pull rhoconnect code from remote repository ..." | tee -a /tmp/bench.log
|
|
27
27
|
git reset --hard HEAD | tee -a /tmp/bench.log 2>&1
|
|
@@ -36,7 +36,7 @@ do
|
|
|
36
36
|
ruby_version=$(rvm current)
|
|
37
37
|
echo "Running benchmarks under $ruby_version ..." | tee -a /tmp/bench.log
|
|
38
38
|
echo "" | tee -a /tmp/bench.log
|
|
39
|
-
ruby bench/bench_runner.rb $RHOCONNECT_HOME 2>&1 | tee -a /tmp/bench.log
|
|
39
|
+
ruby ./bench/bench_runner.rb $RHOCONNECT_HOME 2>&1 | tee -a /tmp/bench.log
|
|
40
40
|
done
|
|
41
41
|
|
|
42
42
|
|
data/bench/run_blob_script.sh
CHANGED
data/bench/run_cud_script.sh
CHANGED
data/bench/run_query_script.sh
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#! /bin/sh
|
|
2
|
+
|
|
3
|
+
timestamp_postfix=$(date +%Y_%m_%d_%H%M%S)
|
|
4
|
+
test_label=query_bench_$timestamp_postfix
|
|
5
|
+
if [ $# -gt 0 ] ; then
|
|
6
|
+
test_label=$1
|
|
7
|
+
fi
|
|
8
|
+
server='default'
|
|
9
|
+
if [ $# -gt 1 ] ; then
|
|
10
|
+
server=$2
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
n_iterations=10
|
|
14
|
+
|
|
15
|
+
# setup the benchmark directory structure
|
|
16
|
+
ruby prepare_bench $test_label query_bench_$timestamp_postfix "1 2 3 5 10"
|
|
17
|
+
|
|
18
|
+
# simulate various number of simultaneous clients
|
|
19
|
+
for n_threads in 1 2 3 5 10
|
|
20
|
+
do
|
|
21
|
+
# simulate variaous number of data records
|
|
22
|
+
for payload in 1 5 10 50 100 250 500
|
|
23
|
+
do
|
|
24
|
+
result_filename=./bench_results/query_bench_$timestamp_postfix/raw_data/query_bench_result.$payload
|
|
25
|
+
ruby bench start 'scripts/test_query_script.rb' 'rhoadmin' '' $server $result_filename $n_threads $n_iterations $payload
|
|
26
|
+
done
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
# once benchmark is finished - process the results
|
|
30
|
+
ruby ./lib/bench/bench_result_processor.rb ./bench_results/query_bench_$timestamp_postfix/raw_data ./bench_results/query_bench_$timestamp_postfix/images
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#! /bin/sh
|
|
2
|
+
|
|
3
|
+
timestamp_postfix=$(date +%Y_%m_%d_%H%M%S)
|
|
4
|
+
n_iterations=100
|
|
5
|
+
#server='http://rhohub-mzverev-c7ca8de3.rhosync.com/api/application'
|
|
6
|
+
server='default'
|
|
7
|
+
|
|
8
|
+
# setup the benchmark directory structure
|
|
9
|
+
ruby prepare_bench 'Rhoconnect SOURCE API benchmark' source_bench_$timestamp_postfix "1 2 5 10 15 20"
|
|
10
|
+
|
|
11
|
+
# simulate various number of simultaneous clients
|
|
12
|
+
for n_threads in 1 2 5 10 15 20
|
|
13
|
+
do
|
|
14
|
+
result_filename=./bench_results/source_bench_$timestamp_postfix/raw_data/source_bench_result.test
|
|
15
|
+
ruby bench start 'scripts/test_source_script.rb' 'rhoadmin' '' $server $result_filename $n_threads $n_iterations
|
|
16
|
+
done
|
|
17
|
+
|
|
18
|
+
# once benchmark is finished - process the results
|
|
19
|
+
ruby ./lib/bench/bench_result_processor.rb ./bench_results/source_bench_$timestamp_postfix/raw_data ./bench_results/source_bench_$timestamp_postfix/images
|
|
20
|
+
|
|
21
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
include BenchHelpers
|
|
2
|
+
bench_log "Runs simple login,clientcreate,clientregister,sync session and validates response"
|
|
3
|
+
|
|
4
|
+
Bench.config do |config|
|
|
5
|
+
config.concurrency ||= 10
|
|
6
|
+
config.iterations ||= 10
|
|
7
|
+
config.datasize ||= 100
|
|
8
|
+
config.main_marker = 'get-cud'
|
|
9
|
+
config.user_name = "benchuser"
|
|
10
|
+
config.password = "password"
|
|
11
|
+
config.get_test_server
|
|
12
|
+
@datasize = Bench.datasize
|
|
13
|
+
@expected = Bench.get_test_data(@datasize)
|
|
14
|
+
@all_objects = "[{\"version\":3},{\"token\":\"%s\"},{\"count\":%i},{\"progress_count\":0},{\"total_count\":%i},{\"insert\":""}]"
|
|
15
|
+
@ack_token = "[{\"version\":3},{\"token\":\"\"},{\"count\":0},{\"progress_count\":%i},{\"total_count\":%i},{}]"
|
|
16
|
+
@api_token = Bench.get_token
|
|
17
|
+
config.request_logging = false
|
|
18
|
+
|
|
19
|
+
# if this is not a distributed run - reset the app
|
|
20
|
+
if not Bench.sync_key
|
|
21
|
+
config.reset_app
|
|
22
|
+
config.set_server_state("test_db_storage:application:#{config.user_name}",@expected)
|
|
23
|
+
config.reset_refresh_time('MockAdapter')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Bench.synchronize do |config|
|
|
28
|
+
break unless Bench.sync_key
|
|
29
|
+
while true
|
|
30
|
+
cur_time = Time.now.to_f
|
|
31
|
+
sync_time = Bench.get_server_value(Bench.sync_key).to_f
|
|
32
|
+
if sync_time > 0.0 and cur_time >= sync_time
|
|
33
|
+
break
|
|
34
|
+
end
|
|
35
|
+
sleep(0.010)
|
|
36
|
+
end
|
|
37
|
+
puts " we have here #{cur_time}, #{sync_time}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Bench.test do |config,session|
|
|
41
|
+
session.post "clientlogin", "#{config.base_url}/clientlogin", :content_type => :json do
|
|
42
|
+
{:login => config.user_name, :password => config.password}.to_json
|
|
43
|
+
end
|
|
44
|
+
session.get "clientcreate", "#{config.base_url}/clientcreate"
|
|
45
|
+
client_id = JSON.parse(session.last_result.body)['client']['client_id']
|
|
46
|
+
session.client_id = client_id
|
|
47
|
+
session.post "clientregister", "#{config.base_url}/clientregister", :content_type => :json do
|
|
48
|
+
{:device_type => "Apple", :device_pin => 'somepin123', :device_port => "device_port_111", :phone_id => 'unique_phone_id',
|
|
49
|
+
:client_id => client_id}.to_json
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
session.get "get-cud", "#{config.base_url}/query" do
|
|
53
|
+
{'source_name' => 'MockAdapter', 'client_id' => session.client_id, 'p_size' => @datasize}
|
|
54
|
+
end
|
|
55
|
+
token = JSON.parse(session.last_result.body)[1]['token']
|
|
56
|
+
session.get "ack-cud", "#{config.base_url}/query" do
|
|
57
|
+
{ 'source_name' => 'MockAdapter',
|
|
58
|
+
'client_id' => session.client_id,
|
|
59
|
+
'token' => token}
|
|
60
|
+
end
|
|
61
|
+
session.last_result.verify_code(200)
|
|
62
|
+
session.last_result.verify_body([{:version => 3},{:token => ''},{:count => 0},
|
|
63
|
+
{:progress_count => @datasize},{:total_count => @datasize},{}].to_json)
|
|
64
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
include BenchHelpers
|
|
2
|
+
bench_log "Runs admin source methods in batch"
|
|
3
|
+
|
|
4
|
+
Bench.config do |config|
|
|
5
|
+
config.concurrency ||= 10
|
|
6
|
+
config.iterations ||= 100
|
|
7
|
+
config.main_marker = 'get_adapter'
|
|
8
|
+
config.user_name = "benchuser"
|
|
9
|
+
config.password = "password"
|
|
10
|
+
config.get_test_server
|
|
11
|
+
config.reset_app
|
|
12
|
+
|
|
13
|
+
@token = config.get_token
|
|
14
|
+
@save_adapter_url = "my/dynamic/adapter/url"
|
|
15
|
+
config.reset_refresh_time('MockAdapter')
|
|
16
|
+
config.request_logging = false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Bench.test do |config,session|
|
|
21
|
+
session.post "save_adapter", "#{config.host}/api/source/save_adapter", :content_type => :json do
|
|
22
|
+
{:api_token => @token, :attributes => {:adapter_url => @save_adapter_url}}.to_json
|
|
23
|
+
end
|
|
24
|
+
session.post "get_adapter", "#{config.host}/api/source/get_adapter", :content_type => :json do
|
|
25
|
+
{:api_token => @token}.to_json
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','bench','lib')
|
|
5
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','bench')
|
|
6
|
+
require 'bench'
|
|
7
|
+
|
|
8
|
+
$ARGV.unshift ''
|
|
9
|
+
$ARGV.unshift 'rhoadmin'
|
|
10
|
+
$ARGV.unshift 'scripts/test_comm_script.rb'
|
|
11
|
+
$ARGV.unshift 'start'
|
|
12
|
+
|
|
13
|
+
Bench::Cli.start
|
data/doc/client-objc.txt
CHANGED
|
@@ -73,6 +73,8 @@ Do the following steps to add schema files to your Copy Bundle Resources build p
|
|
|
73
73
|
CREATE TABLE product (
|
|
74
74
|
"client_id" VARCHAR(255) default NULL);
|
|
75
75
|
|
|
76
|
+
** NOTE: Do not use NOT NULL statement in column definitions. RhoConnect client delete object attributes by setting value to null, when all object attributes become nulls, object deleted. So objects with NOT NULL columns will not be deleted. **
|
|
77
|
+
|
|
76
78
|
## Coding a RhoConnect Client
|
|
77
79
|
|
|
78
80
|
This section discusses the general steps you perform to code a RhoConnect client in Objective C, using the store example. It is not a tutorial for coding a complete Xcode application, but instead discusses the RhoConnect code that you need to create.
|
|
@@ -180,6 +182,7 @@ Here is the Store code for the login process, contained in LoginViewController.m
|
|
|
180
182
|
[ [RhoConnectEngine sharedInstance].syncClient loginWithUser:txtLogin.text pwd:txtPassword.text callback:@selector(loginComplete:) target:self];
|
|
181
183
|
}
|
|
182
184
|
|
|
185
|
+
|
|
183
186
|
### Synchronize Data
|
|
184
187
|
|
|
185
188
|
Call the RhoConnectClient setNotification method to call a callback method that notifies about the state of the synchronization.
|
|
@@ -210,6 +213,31 @@ Here is the Store code for the sync process, contained in WaitLoginController.m.
|
|
|
210
213
|
[ [RhoConnectEngine sharedInstance].syncClient clearNotification];
|
|
211
214
|
}else if ([notify.status compare:@"error"] == 0)
|
|
212
215
|
{
|
|
216
|
+
if([notify.error_message caseInsensitiveCompare:@"unknown client"] == 0) {
|
|
217
|
+
[[RhoConnectEngine sharedInstance].syncClient database_client_reset];
|
|
218
|
+
[[RhoConnectEngine sharedInstance].syncClient setNotification: @selector(syncAllCalback:) target:self];
|
|
219
|
+
[[RhoConnectEngine sharedInstance].syncClient syncAll];
|
|
220
|
+
} else if( err_code == RHO_ERR_CLIENTISNOTLOGGEDIN
|
|
221
|
+
|| err_code == RHO_ERR_UNATHORIZED) {
|
|
222
|
+
|
|
223
|
+
NSLog(@"GO TO LOGIN PAGE!");
|
|
224
|
+
// real code to trigger view transition goes here..
|
|
225
|
+
}else
|
|
226
|
+
{
|
|
227
|
+
//This is mandatory:
|
|
228
|
+
if([notify hasCreateErrors]) {
|
|
229
|
+
[[RhoConnectEngine sharedInstance].syncClient onCreateError: notify @"delete"];
|
|
230
|
+
}
|
|
231
|
+
//These are optional:
|
|
232
|
+
/*
|
|
233
|
+
if([notify hasUpdateErrors]) {
|
|
234
|
+
[[RhoConnectEngine sharedInstance].syncClient onUpdateError: notify @"rollback"];
|
|
235
|
+
}
|
|
236
|
+
if([notify hasDeleteErrors]) {
|
|
237
|
+
[[RhoConnectEngine sharedInstance].syncClient onDeleteError: notify @"retry"];
|
|
238
|
+
}
|
|
239
|
+
*/
|
|
240
|
+
}
|
|
213
241
|
}
|
|
214
242
|
}
|
|
215
243
|
|
|
@@ -227,6 +255,114 @@ Here is the Store code for the sync process, contained in WaitLoginController.m.
|
|
|
227
255
|
}
|
|
228
256
|
}
|
|
229
257
|
|
|
258
|
+
### Processing unknown-client error
|
|
259
|
+
Unknown client error return by server after resetting server database, removing particular client id from database or any other cases when server cannot find client id(sync server unique id of device).
|
|
260
|
+
Note that login session may still exist on server, so in this case client does not have to login again, just create new client id.
|
|
261
|
+
Processing of this error contain 2 steps:
|
|
262
|
+
|
|
263
|
+
* When unknown client error is come from server, client should call database_client_reset and start new sync, to register new client id.
|
|
264
|
+
|
|
265
|
+
* If login session also deleted or expired on the server, then customer has to login again.
|
|
266
|
+
|
|
267
|
+
Example:
|
|
268
|
+
:::cplusplus
|
|
269
|
+
|
|
270
|
+
- (void)syncAllComplete:(RhoConnectNotify*) notify
|
|
271
|
+
{
|
|
272
|
+
NSString* status = notify.status;
|
|
273
|
+
NSString* error = notify.error_message;
|
|
274
|
+
int err_code = notify.error_code;
|
|
275
|
+
|
|
276
|
+
NSLog(@"syncAll DONE, status: '%s' , error_msg: '%s' , error_code: %d",
|
|
277
|
+
[status cStringUsingEncoding: NSUTF8StringEncoding],
|
|
278
|
+
[error cStringUsingEncoding: NSUTF8StringEncoding],
|
|
279
|
+
err_code
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
if ( [notify.status compare:@"in_progress"] == 0) {
|
|
283
|
+
|
|
284
|
+
} else if ([notify.status compare:@"complete"] == 0) {
|
|
285
|
+
|
|
286
|
+
[[RhoConnectEngine sharedInstance].syncClient clearNotification];
|
|
287
|
+
|
|
288
|
+
} else if ([notify.status compare:@"error"] == 0) {
|
|
289
|
+
|
|
290
|
+
if([notify.error_message caseInsensitiveCompare:@"unknown client"] == 0) {
|
|
291
|
+
[[RhoConnectEngine sharedInstance].syncClient database_client_reset];
|
|
292
|
+
[[RhoConnectEngine sharedInstance].syncClient setNotification: @selector(syncAllCalback:) target:self];
|
|
293
|
+
[[RhoConnectEngine sharedInstance].syncClient syncAll];
|
|
294
|
+
} else if( err_code == RHO_ERR_CLIENTISNOTLOGGEDIN
|
|
295
|
+
|| err_code == RHO_ERR_UNATHORIZED) {
|
|
296
|
+
|
|
297
|
+
NSLog(@"GO TO LOGIN PAGE!");
|
|
298
|
+
// real code to trigger view transition goes here..
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
### Processing server errors
|
|
304
|
+
* create-error:
|
|
305
|
+
has to be handled in sync callback. Otherwise sync will stop on this model. To fix create errors you should call Model.on_sync_create_error or SyncEngine.on_sync_create_error:
|
|
306
|
+
|
|
307
|
+
* update-error:
|
|
308
|
+
If not handled, local modifications, which were failing on server, will never sync to server again.
|
|
309
|
+
So sync will work fine, but nobody will know about these changes.
|
|
310
|
+
|
|
311
|
+
* delete-error:
|
|
312
|
+
If not handled, local modifications, which were failing on server, will never sync to server again.
|
|
313
|
+
So sync will work fine, but nobody will know about these changes.
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
:::cplusplus
|
|
317
|
+
|
|
318
|
+
- (void)syncAllCalback:(RhoConnectNotify*) notify
|
|
319
|
+
{
|
|
320
|
+
NSString* status = notify.status;
|
|
321
|
+
NSString* error = notify.error_message;
|
|
322
|
+
int err_code = notify.error_code;
|
|
323
|
+
|
|
324
|
+
NSLog(@"syncAll DONE, status: '%s' , error_msg: '%s' , error_code: %d",
|
|
325
|
+
[status cStringUsingEncoding: NSUTF8StringEncoding],
|
|
326
|
+
[error cStringUsingEncoding: NSUTF8StringEncoding],
|
|
327
|
+
err_code
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
if ( [notify.status compare:@"in_progress"] == 0) {
|
|
331
|
+
|
|
332
|
+
} else if ([notify.status compare:@"complete"] == 0) {
|
|
333
|
+
|
|
334
|
+
[[RhoConnectEngine sharedInstance].syncClient clearNotification];
|
|
335
|
+
|
|
336
|
+
} else if ([notify.status compare:@"error"] == 0) {
|
|
337
|
+
|
|
338
|
+
if([notify isUnknownClientError]) {
|
|
339
|
+
[[RhoConnectEngine sharedInstance].syncClient database_client_reset];
|
|
340
|
+
[[RhoConnectEngine sharedInstance].syncClient setNotification: @selector(syncAllCalback:) target:self];
|
|
341
|
+
[[RhoConnectEngine sharedInstance].syncClient syncAll];
|
|
342
|
+
} else if( err_code == RHO_ERR_CLIENTISNOTLOGGEDIN
|
|
343
|
+
|| err_code == RHO_ERR_UNATHORIZED) {
|
|
344
|
+
|
|
345
|
+
NSLog(@"GO TO LOGIN PAGE!");
|
|
346
|
+
// real code to trigger view transition goes here..
|
|
347
|
+
}else
|
|
348
|
+
{
|
|
349
|
+
//This is mandatory:
|
|
350
|
+
if([notify hasCreateErrors]) {
|
|
351
|
+
[[RhoConnectEngine sharedInstance].syncClient onCreateError: notify action:@"delete"];
|
|
352
|
+
}
|
|
353
|
+
//These are optional:
|
|
354
|
+
/*
|
|
355
|
+
if([notify hasUpdateErrors]) {
|
|
356
|
+
[[RhoConnectEngine sharedInstance].syncClient onUpdateError: notify action:@"rollback"];
|
|
357
|
+
}
|
|
358
|
+
if([notify hasDeleteErrors]) {
|
|
359
|
+
[[RhoConnectEngine sharedInstance].syncClient onDeleteError: notify action:@"retry"];
|
|
360
|
+
}
|
|
361
|
+
*/
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
230
366
|
### Search the Client Database for Models
|
|
231
367
|
|
|
232
368
|
Call a RhomModel find method (find, find\_first, find\_all) to find model objects in the client database. This code sample for the find\_all method fetches all the models in the database; you can also search for models containing certain attribute data.
|
|
@@ -271,6 +407,9 @@ The RhoConnectClient class contains the following properties and methods to buil
|
|
|
271
407
|
* <a href="#setObjectNotification">setObjectNotification</a>
|
|
272
408
|
* <a href="#clearObjectNotification">clearObjectNotification</a>
|
|
273
409
|
* <a href="#addObjectNotify">addObjectNotify</a>
|
|
410
|
+
* <a href="#onCreateError">onCreateError</a>
|
|
411
|
+
* <a href="#onUpdateError">onUpdateError</a>
|
|
412
|
+
* <a href="#onDeleteError">onDeleteError</a>
|
|
274
413
|
|
|
275
414
|
### <a id="threaded_mode"></a>threaded\_mode property
|
|
276
415
|
|
|
@@ -477,7 +616,86 @@ Sample call:
|
|
|
477
616
|
RhoConnectClient* sclient;
|
|
478
617
|
...
|
|
479
618
|
[sclient addObjectNotify: [[item objectForKey:@"source_id"] intValue] szObject:[item valueForKey:@"object"] ];
|
|
480
|
-
|
|
619
|
+
|
|
620
|
+
### <a id="onCreateError"></a>onCreateError
|
|
621
|
+
|
|
622
|
+
Instance method. To process 'create-error' errors from server.
|
|
623
|
+
|
|
624
|
+
:::cplusplus
|
|
625
|
+
- (void) onCreateError: (RhoConnectNotify*)notify action: (NSString*)action;
|
|
626
|
+
|
|
627
|
+
<table border="1">
|
|
628
|
+
<tr>
|
|
629
|
+
<td><code>notify</code></td>
|
|
630
|
+
<td>RhoConnectNotify. Notification object passed to notification callback.</td>
|
|
631
|
+
</tr>
|
|
632
|
+
<tr>
|
|
633
|
+
<td><code>action</code></td>
|
|
634
|
+
<td>NSString. May be "delete" or "recreate": "delete" just remove object from client, "recreate" will push this object to server again at next sync.</td>
|
|
635
|
+
</tr>
|
|
636
|
+
</table>
|
|
637
|
+
|
|
638
|
+
Sample call:
|
|
639
|
+
|
|
640
|
+
:::cplusplus
|
|
641
|
+
RhoConnectClient* sclient;
|
|
642
|
+
...
|
|
643
|
+
if ([notify hasCreateErrors])
|
|
644
|
+
[sclient onCreateError: notify action:@"delete" ];
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
### <a id="onUpdateError"></a>onUpdateError
|
|
648
|
+
|
|
649
|
+
Instance method. To process 'update-error' errors from server.
|
|
650
|
+
|
|
651
|
+
:::cplusplus
|
|
652
|
+
- (void) onUpdateError: (RhoConnectNotify*)notify action: (NSString*)action;
|
|
653
|
+
|
|
654
|
+
<table border="1">
|
|
655
|
+
<tr>
|
|
656
|
+
<td><code>notify</code></td>
|
|
657
|
+
<td>RhoConnectNotify. Notification object passed to notification callback.</td>
|
|
658
|
+
</tr>
|
|
659
|
+
<tr>
|
|
660
|
+
<td><code>action</code></td>
|
|
661
|
+
<td>NSString. May be "retry" or "rollback": "retry" will push update object operation to server again at next sync, "rollback" will write rollback objects(comes from server) to client database.</td>
|
|
662
|
+
</tr>
|
|
663
|
+
</table>
|
|
664
|
+
|
|
665
|
+
Sample call:
|
|
666
|
+
|
|
667
|
+
:::cplusplus
|
|
668
|
+
RhoConnectClient* sclient;
|
|
669
|
+
...
|
|
670
|
+
if ([notify hasUpdateErrors])
|
|
671
|
+
[sclient onUpdateError: notify action:@"retry" ];
|
|
672
|
+
|
|
673
|
+
### <a id="onDeleteError"></a>onUpdateError
|
|
674
|
+
|
|
675
|
+
Instance method. To process 'delete-error' errors from server.
|
|
676
|
+
|
|
677
|
+
:::cplusplus
|
|
678
|
+
- (void) onDeleteError: (RhoConnectNotify*)notify action: (NSString*)action;
|
|
679
|
+
|
|
680
|
+
<table border="1">
|
|
681
|
+
<tr>
|
|
682
|
+
<td><code>notify</code></td>
|
|
683
|
+
<td>RhoConnectNotify. Notification object passed to notification callback.</td>
|
|
684
|
+
</tr>
|
|
685
|
+
<tr>
|
|
686
|
+
<td><code>action</code></td>
|
|
687
|
+
<td>NSString. May be "retry" - will push delete object operation to server again at next sync.</td>
|
|
688
|
+
</tr>
|
|
689
|
+
</table>
|
|
690
|
+
|
|
691
|
+
Sample call:
|
|
692
|
+
|
|
693
|
+
:::cplusplus
|
|
694
|
+
RhoConnectClient* sclient;
|
|
695
|
+
...
|
|
696
|
+
if ([notify hasDeleteErrors])
|
|
697
|
+
[sclient onDeleteError: notify action:@"retry" ];
|
|
698
|
+
|
|
481
699
|
## RhomModel Class API
|
|
482
700
|
|
|
483
701
|
The RhomModel class contains the following properties and methods for setting and using RhomModel objects; RhomModel objects are RhoConnect models and their attributes.
|
|
@@ -751,6 +969,23 @@ Several RhoConnectClient methods return a RhoConnectNotify object. The propertie
|
|
|
751
969
|
<td><code>callback_params</code></td>
|
|
752
970
|
<td>@property(assign) NSString*. Callback parameters.</td>
|
|
753
971
|
</tr>
|
|
972
|
+
<tr>
|
|
973
|
+
<td><code>hasCreateErrors</code></td>
|
|
974
|
+
<td>(Boolean). Return true if server return create-errors.</td>
|
|
975
|
+
</tr>
|
|
976
|
+
<tr>
|
|
977
|
+
<td><code>hasUpdateErrors</code></td>
|
|
978
|
+
<td>(Boolean). Return true if server return update-errors.</td>
|
|
979
|
+
</tr>
|
|
980
|
+
<tr>
|
|
981
|
+
<td><code>hasDeleteErrors</code></td>
|
|
982
|
+
<td>(Boolean). Return true if server return delete-errors.</td>
|
|
983
|
+
</tr>
|
|
984
|
+
<tr>
|
|
985
|
+
<td><code>isUnknownClientError</code></td>
|
|
986
|
+
<td>(Boolean). Return true if server return unknown client error.</td>
|
|
987
|
+
</tr>
|
|
988
|
+
|
|
754
989
|
</table>
|
|
755
990
|
|
|
756
991
|
## RhoConnectObjectNotify Class API
|