]> git.proxmox.com Git - sencha-touch.git/blob - src/src/platform/src/data/sync/Protocol.js
import Sencha Touch 2.4.2 source
[sencha-touch.git] / src / src / platform / src / data / sync / Protocol.js
1
2 Ext.data.Protocol = Ext.extend(Object, {
3
4 constructor: function(config) {
5 this.remote = config.remoteStorageProxy;
6 this.remote.on('exception',function(proxy,request,operation){
7 console.log('EXCEPTION'); // JCM should handle this properly...
8 console.log(request);
9 console.log(operation);
10 });
11 },
12
13 sync: function(local, callback, scope) {
14 //
15 // JCM callback if something is going to take a long time...
16 // JCM like changing the replica number
17 // JCM or clearing after a generation change
18 //
19 if (callback===undefined) { callback= function(){}; } // JCM maybe should warn the caller...
20 this.send_create_database(local.definition,function(operation) {
21 var response= operation.response;
22 switch (response.r) {
23 case 'ok':
24 //
25 // The remote CSV describes the state of updated-ness of the
26 // server this client is talking to. We add any replica numbers
27 // that are new to us to our local CSV.
28 //
29 var remote_csv= response.csv;
30 local.addReplicaNumbers(remote_csv);
31 this.sync_datastore(local,remote_csv,callback,scope);
32 break;
33 case 'new_replica_number':
34 //
35 // A replica number collision, or re-initialization, has occured.
36 // In either case we must change our local replica number.
37 //
38 local.setReplicaNumber(response.replica_number,function(){
39 this.sync(local,callback,scope); // JCM beware of infinite loop
40 },this);
41 break;
42 case 'new_generation_number':
43 //
44 // The database generation has changed. We clear out the database,
45 // and update the definition.
46 //
47 if (response.generation>local.definition.generation) {
48 local.definition.set({generation:response.generation},function(){
49 local.clear(function(){
50 this.sync(local,callback,scope); // JCM beware of infinite loop
51 },this);
52 },this);
53 } else {
54 // local is the same, or greater than the server.
55 }
56 break;
57 default:
58 callback.call(scope);
59 break;
60 }
61 },this);
62 },
63
64 // @private
65 sync_datastore: function(local, remote_csv, callback, scope) {
66 //
67 // JCM In theory... we could send and receive at the same time...
68 //
69 local.getUpdates(remote_csv,function(updates){
70 this.put_database_updates(local.definition,updates,function(operation){
71 if (remote_csv.dominates(local.csv)) {
72 this.get_database_updates(local,callback,scope);
73 } else {
74 callback.call(scope);
75 }
76 },this);
77 },this);
78 },
79
80 send_create_database: function(definition,callback,scope) {
81 var request= definition.encode();
82 this.sendRequest(definition.database_name,'edit',request,function(operation){
83 var response= operation.response;
84 if (response.csv) {
85 response.csv= new Ext.data.CSV().decode(response.csv);
86 }
87 callback.call(scope, operation);
88 },this);
89 },
90
91 put_database_updates: function(definition,updates,callback,scope) {
92 //
93 // When sending updates through the ScriptTagProxy the data is
94 // encoded as a URL, so there is a browser imposed limit on the
95 // length of that URL. So, let's be prudent and limit the amount
96 // of data sent at a time.
97 //
98 var chunks= updates.chunks(1000); // JCM count of updates... should be K?
99 Ext.data.array.forEachYielding(chunks,function(chunk,next_callback,next_scope){
100 this.send_put_database_updates(definition,chunk,function(operation){
101 //if (operation.response.r=='ok') {
102 // keep going
103 //} else {
104 // JCM abort... but how?
105 //}
106 next_callback.call(next_scope);
107 },this);
108 },this,callback,scope);
109 },
110
111 send_put_database_updates: function(definition,updates,callback,scope) {
112 if (!updates.isEmpty()) {
113 var request= {
114 updates: Ext.encode(updates.encode())
115 };
116 this.sendRequest(definition.database_name,'put_updates',request,callback,scope);
117 } else {
118 var operation= this.encodeRequest({});
119 operation.response= {r:"ok"};
120 callback.call(scope, operation);
121 }
122 },
123
124 get_database_updates: function(local,callback,scope) {
125 this.send_get_database_updates(local.definition,local.csv,function(operation){
126 //
127 // JCM perhaps an 'event' should be fired for each object changed
128 // JCM which serves as a trigger for the UI to update
129 //
130 var response= operation.response;
131 if (response.r=='ok') {
132 local.putUpdates(response.updates,function() {
133 if (response.remaining>0 && !response.updates.isEmpty()) {
134 this.get_database_updates(local,callback,scope);
135 } else {
136 callback.call(scope);
137 }
138 },this);
139 } else {
140 callback.call(scope);
141 }
142 },this);
143 },
144
145 send_get_database_updates: function(definition,csv,callback,scope) {
146 var request= {
147 csv: csv.encode()
148 };
149 this.sendRequest(definition.database_name,'get_updates',request,function(operation){
150 var response= operation.response;
151 response.updates= new Ext.data.Updates().decode(response.updates);
152 callback.call(scope, operation);
153 },this);
154 },
155
156 sendRequest: function(database_name,method,request,callback,scope) {
157 var operation= this.encodeRequest(database_name,method,request);
158 var debug= true; // JCM
159 if (debug) {
160 console.log("local ->",this.remote.url,method,Ext.encode(request));
161 }
162 this.remote.read(operation,function(operation){
163 if (debug) {
164 console.log(" sent",operation.request.url.length,"bytes -",operation.request.url);
165 console.log(" <= ",method,Ext.encode(operation.response));
166 }
167 callback.call(scope, operation);
168 },this);
169 },
170
171 encodeRequest: function(database_name,method,request) {
172 var text= Ext.encode(request);
173 var url= this.remote.url+"database/"+database_name+"/"+method;
174 return new Ext.data.Operation({
175 filters: [],
176 action: 'read',
177 url: url,
178 params: request
179 });
180 return operation;
181 }
182
183 });