rhosync 2.0.0.beta1

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.
Files changed (200) hide show
  1. data/CHANGELOG +5 -0
  2. data/LICENSE +674 -0
  3. data/README.md +26 -0
  4. data/Rakefile +109 -0
  5. data/bench/bench +6 -0
  6. data/bench/benchapp/Rakefile +14 -0
  7. data/bench/benchapp/application.rb +13 -0
  8. data/bench/benchapp/config.ru +32 -0
  9. data/bench/benchapp/settings/license.key +1 -0
  10. data/bench/benchapp/settings/settings.yml +18 -0
  11. data/bench/benchapp/sources/mock_adapter.rb +55 -0
  12. data/bench/benchapp/sources/queue_mock_adapter.rb +2 -0
  13. data/bench/benchapp/vendor/rhosync/lib/rhosync.rb +7 -0
  14. data/bench/lib/bench/cli.rb +16 -0
  15. data/bench/lib/bench/logging.rb +18 -0
  16. data/bench/lib/bench/mock_client.rb +41 -0
  17. data/bench/lib/bench/result.rb +50 -0
  18. data/bench/lib/bench/runner.rb +44 -0
  19. data/bench/lib/bench/session.rb +65 -0
  20. data/bench/lib/bench/statistics.rb +56 -0
  21. data/bench/lib/bench/test_data.rb +55 -0
  22. data/bench/lib/bench/timer.rb +10 -0
  23. data/bench/lib/bench/utils.rb +49 -0
  24. data/bench/lib/bench.rb +128 -0
  25. data/bench/lib/testdata/100-data.txt +148 -0
  26. data/bench/lib/testdata/5-data.txt +11 -0
  27. data/bench/scripts/cud_script.rb +77 -0
  28. data/bench/scripts/helpers.rb +101 -0
  29. data/bench/scripts/query_md_script.rb +46 -0
  30. data/bench/scripts/query_script.rb +46 -0
  31. data/bench/spec/bench_spec_helper.rb +65 -0
  32. data/bench/spec/logging_spec.rb +19 -0
  33. data/bench/spec/mock_adapter_spec.rb +61 -0
  34. data/bench/spec/mock_client_spec.rb +64 -0
  35. data/bench/spec/result_spec.rb +59 -0
  36. data/bench/spec/utils_spec.rb +35 -0
  37. data/bin/rhosync +34 -0
  38. data/doc/protocol.html +1901 -0
  39. data/doc/public/css/print.css +29 -0
  40. data/doc/public/css/screen.css +257 -0
  41. data/doc/public/css/style.css +20 -0
  42. data/examples/simple/application.rb +13 -0
  43. data/examples/simple/sources/sample_adapter.rb +5 -0
  44. data/examples/simple/sources/simple_adapter.rb +5 -0
  45. data/examples/simple/vendor/rhosync/lib/rhosync.rb +7 -0
  46. data/generators/rhosync.rb +98 -0
  47. data/generators/templates/application/Rakefile +19 -0
  48. data/generators/templates/application/application.rb +27 -0
  49. data/generators/templates/application/config.ru +33 -0
  50. data/generators/templates/application/settings/license.key +1 -0
  51. data/generators/templates/application/settings/settings.yml +14 -0
  52. data/generators/templates/source/source_adapter.rb +49 -0
  53. data/lib/rhosync/api/create_client.rb +3 -0
  54. data/lib/rhosync/api/create_user.rb +7 -0
  55. data/lib/rhosync/api/delete_client.rb +5 -0
  56. data/lib/rhosync/api/delete_user.rb +5 -0
  57. data/lib/rhosync/api/get_api_token.rb +7 -0
  58. data/lib/rhosync/api/get_client_params.rb +3 -0
  59. data/lib/rhosync/api/get_db_doc.rb +7 -0
  60. data/lib/rhosync/api/get_license_info.rb +7 -0
  61. data/lib/rhosync/api/get_source_params.rb +3 -0
  62. data/lib/rhosync/api/list_client_docs.rb +12 -0
  63. data/lib/rhosync/api/list_clients.rb +3 -0
  64. data/lib/rhosync/api/list_source_docs.rb +10 -0
  65. data/lib/rhosync/api/list_sources.rb +15 -0
  66. data/lib/rhosync/api/list_users.rb +3 -0
  67. data/lib/rhosync/api/ping.rb +7 -0
  68. data/lib/rhosync/api/push_deletes.rb +6 -0
  69. data/lib/rhosync/api/push_objects.rb +6 -0
  70. data/lib/rhosync/api/reset.rb +10 -0
  71. data/lib/rhosync/api/set_db_doc.rb +8 -0
  72. data/lib/rhosync/api/set_refresh_time.rb +8 -0
  73. data/lib/rhosync/api/update_user.rb +4 -0
  74. data/lib/rhosync/api/upload_file.rb +4 -0
  75. data/lib/rhosync/api_token.rb +19 -0
  76. data/lib/rhosync/app.rb +69 -0
  77. data/lib/rhosync/bulk_data/bulk_data.rb +75 -0
  78. data/lib/rhosync/bulk_data/syncdb.index.schema +3 -0
  79. data/lib/rhosync/bulk_data/syncdb.schema +37 -0
  80. data/lib/rhosync/bulk_data.rb +2 -0
  81. data/lib/rhosync/client.rb +74 -0
  82. data/lib/rhosync/client_sync.rb +296 -0
  83. data/lib/rhosync/console/app/helpers/auth_helper.rb +18 -0
  84. data/lib/rhosync/console/app/helpers/extensions.rb +19 -0
  85. data/lib/rhosync/console/app/helpers/helpers.rb +52 -0
  86. data/lib/rhosync/console/app/public/main.css +7 -0
  87. data/lib/rhosync/console/app/public/text.txt +0 -0
  88. data/lib/rhosync/console/app/routes/auth.rb +29 -0
  89. data/lib/rhosync/console/app/routes/client.rb +32 -0
  90. data/lib/rhosync/console/app/routes/docs.rb +84 -0
  91. data/lib/rhosync/console/app/routes/home.rb +22 -0
  92. data/lib/rhosync/console/app/routes/user.rb +63 -0
  93. data/lib/rhosync/console/app/views/client.erb +30 -0
  94. data/lib/rhosync/console/app/views/doc.erb +56 -0
  95. data/lib/rhosync/console/app/views/docs.erb +29 -0
  96. data/lib/rhosync/console/app/views/index.erb +50 -0
  97. data/lib/rhosync/console/app/views/layout.erb +12 -0
  98. data/lib/rhosync/console/app/views/newuser.erb +17 -0
  99. data/lib/rhosync/console/app/views/ping.erb +28 -0
  100. data/lib/rhosync/console/app/views/result.erb +11 -0
  101. data/lib/rhosync/console/app/views/user.erb +32 -0
  102. data/lib/rhosync/console/app/views/users.erb +14 -0
  103. data/lib/rhosync/console/rhosync_api.rb +102 -0
  104. data/lib/rhosync/console/server.rb +27 -0
  105. data/lib/rhosync/credential.rb +9 -0
  106. data/lib/rhosync/document.rb +43 -0
  107. data/lib/rhosync/indifferent_access.rb +132 -0
  108. data/lib/rhosync/jobs/bulk_data_job.rb +104 -0
  109. data/lib/rhosync/jobs/ping_job.rb +19 -0
  110. data/lib/rhosync/jobs/source_job.rb +16 -0
  111. data/lib/rhosync/license.rb +79 -0
  112. data/lib/rhosync/lock_ops.rb +11 -0
  113. data/lib/rhosync/model.rb +410 -0
  114. data/lib/rhosync/ping/blackberry.rb +55 -0
  115. data/lib/rhosync/ping/iphone.rb +44 -0
  116. data/lib/rhosync/ping.rb +2 -0
  117. data/lib/rhosync/read_state.rb +27 -0
  118. data/lib/rhosync/server/views/index.erb +12 -0
  119. data/lib/rhosync/server.rb +242 -0
  120. data/lib/rhosync/source.rb +112 -0
  121. data/lib/rhosync/source_adapter.rb +95 -0
  122. data/lib/rhosync/source_sync.rb +245 -0
  123. data/lib/rhosync/store.rb +199 -0
  124. data/lib/rhosync/tasks.rb +151 -0
  125. data/lib/rhosync/user.rb +83 -0
  126. data/lib/rhosync/version.rb +3 -0
  127. data/lib/rhosync.rb +251 -0
  128. data/spec/api/api_helper.rb +44 -0
  129. data/spec/api/create_client_spec.rb +13 -0
  130. data/spec/api/create_user_spec.rb +16 -0
  131. data/spec/api/delete_client_spec.rb +13 -0
  132. data/spec/api/delete_user_spec.rb +18 -0
  133. data/spec/api/get_api_token_spec.rb +25 -0
  134. data/spec/api/get_client_params_spec.rb +18 -0
  135. data/spec/api/get_db_doc_spec.rb +21 -0
  136. data/spec/api/get_license_info_spec.rb +16 -0
  137. data/spec/api/get_source_params_spec.rb +26 -0
  138. data/spec/api/list_client_docs_spec.rb +33 -0
  139. data/spec/api/list_clients_spec.rb +23 -0
  140. data/spec/api/list_source_docs_spec.rb +26 -0
  141. data/spec/api/list_sources_spec.rb +27 -0
  142. data/spec/api/list_users_spec.rb +21 -0
  143. data/spec/api/ping_spec.rb +24 -0
  144. data/spec/api/push_deletes_spec.rb +16 -0
  145. data/spec/api/push_objects_spec.rb +27 -0
  146. data/spec/api/reset_spec.rb +22 -0
  147. data/spec/api/set_db_doc_spec.rb +20 -0
  148. data/spec/api/set_refresh_time_spec.rb +43 -0
  149. data/spec/api/update_user_spec.rb +31 -0
  150. data/spec/api/upload_file_spec.rb +26 -0
  151. data/spec/api_token_spec.rb +13 -0
  152. data/spec/app_spec.rb +20 -0
  153. data/spec/apps/rhotestapp/Rakefile +1 -0
  154. data/spec/apps/rhotestapp/application.rb +16 -0
  155. data/spec/apps/rhotestapp/config.ru +1 -0
  156. data/spec/apps/rhotestapp/settings/apple_fake_cert.pem +1 -0
  157. data/spec/apps/rhotestapp/settings/license.key +1 -0
  158. data/spec/apps/rhotestapp/settings/settings.yml +23 -0
  159. data/spec/apps/rhotestapp/sources/base_adapter.rb +9 -0
  160. data/spec/apps/rhotestapp/sources/sample_adapter.rb +66 -0
  161. data/spec/apps/rhotestapp/sources/simple_adapter.rb +39 -0
  162. data/spec/apps/rhotestapp/sources/sub_adapter.rb +7 -0
  163. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem/mygem.rb +8 -0
  164. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem.rb +1 -0
  165. data/spec/bulk_data/bulk_data_spec.rb +79 -0
  166. data/spec/client_spec.rb +58 -0
  167. data/spec/client_sync_spec.rb +377 -0
  168. data/spec/doc/base.html +72 -0
  169. data/spec/doc/doc_spec.rb +303 -0
  170. data/spec/doc/footer.html +4 -0
  171. data/spec/doc/header.html +30 -0
  172. data/spec/document_spec.rb +27 -0
  173. data/spec/generator/generator_spec.rb +53 -0
  174. data/spec/generator/generator_spec_helper.rb +8 -0
  175. data/spec/jobs/bulk_data_job_spec.rb +76 -0
  176. data/spec/jobs/ping_job_spec.rb +26 -0
  177. data/spec/jobs/source_job_spec.rb +25 -0
  178. data/spec/license_spec.rb +48 -0
  179. data/spec/model_spec.rb +269 -0
  180. data/spec/perf/bulk_data_perf_spec.rb +33 -0
  181. data/spec/perf/perf_spec_helper.rb +51 -0
  182. data/spec/perf/store_perf_spec.rb +28 -0
  183. data/spec/ping/blackberry_spec.rb +62 -0
  184. data/spec/ping/iphone_spec.rb +50 -0
  185. data/spec/read_state_spec.rb +25 -0
  186. data/spec/rhosync_spec.rb +43 -0
  187. data/spec/server/server_spec.rb +341 -0
  188. data/spec/source_adapter_spec.rb +114 -0
  189. data/spec/source_spec.rb +77 -0
  190. data/spec/source_sync_spec.rb +248 -0
  191. data/spec/spec_helper.rb +240 -0
  192. data/spec/store_spec.rb +149 -0
  193. data/spec/sync_states_spec.rb +101 -0
  194. data/spec/testdata/1000-data.txt +1414 -0
  195. data/spec/testdata/compressed/compress-data.txt +1 -0
  196. data/spec/testdata/upload1.txt +1 -0
  197. data/spec/testdata/upload2.txt +1 -0
  198. data/spec/user_spec.rb +79 -0
  199. data/tasks/redis.rake +134 -0
  200. metadata +545 -0
@@ -0,0 +1,410 @@
1
+ module Rhosync
2
+ # Taken from http://github.com/voloko/redis-model
3
+ #
4
+ # Simple models for redis-rb.
5
+
6
+ class Model
7
+ attr_accessor :id
8
+
9
+ def initialize(id=nil)
10
+ self.id = id
11
+ end
12
+
13
+ def redis #:nodoc:
14
+ self.class.redis
15
+ end
16
+
17
+ # Issues delete commands for all defined fields
18
+ def delete(name = nil)
19
+ if name
20
+ redis.del field_key(name.to_s)
21
+ else
22
+ self.class.fields.each do |field|
23
+ redis.del field_key(field[:name])
24
+ end
25
+ end
26
+ end
27
+
28
+ def field_key(name) #:nodoc:
29
+ self.class._field_key(prefix,id,name)
30
+ end
31
+
32
+ # Increment the specified integer field by 1 or the
33
+ # specified amount.
34
+ def increment!(name,amount=1)
35
+ raise ArgumentError, "Only integer fields can be incremented." unless self.class.fields.include?({:name => name.to_s, :type => :integer})
36
+ redis.incr(field_key(name), amount)
37
+ end
38
+
39
+ # Decrement the specified integer field by 1 or the
40
+ # specified amount.
41
+ def decrement!(name,amount=1)
42
+ raise ArgumentError, "Only integer fields can be decremented." unless self.class.fields.include?({:name => name.to_s, :type => :integer})
43
+ redis.decr(field_key(name), amount)
44
+ end
45
+
46
+ def next_id #:nodoc:
47
+ redis.incr "sequence:#{self.prefix}:id"
48
+ end
49
+
50
+ def self.is_exist?(id)
51
+ !redis.get(self._field_key(self._prefix,id,'rho__id')).nil?
52
+ end
53
+
54
+ def to_array
55
+ res = []
56
+ self.class.fields.each do |field|
57
+ res << field.merge!(:value => send(field[:name].to_sym))
58
+ end
59
+ res
60
+ end
61
+
62
+ def update(attribs)
63
+ self.class.fields.each do |field|
64
+ if field[:name] != 'name' and field[:name] != 'rho__id'
65
+ redis.del field_key(field[:name])
66
+ end
67
+ end
68
+ self.class.populate_attributes(self,attribs)
69
+ end
70
+
71
+ protected
72
+ def prefix #:nodoc:
73
+ @prefix ||= self.class.prefix || self.class.class_prefix(self.class)
74
+ end
75
+
76
+ class << self
77
+ # Defaults to model_name.dasherize
78
+ attr_accessor :prefix
79
+ attr_accessor :validates_presence
80
+
81
+ def _prefix
82
+ class_prefix(self)
83
+ end
84
+
85
+ def _field_key(p,i,n) #:nodoc:
86
+ "#{p}:#{i}:#{n}"
87
+ end
88
+
89
+ def class_prefix(classname)
90
+ classname.to_s.
91
+ sub(%r{(.*::)}, '').
92
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
93
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
94
+ downcase
95
+ end
96
+
97
+ # Creates new model instance with new uniqid
98
+ # NOTE: "sequence:model_name:id" key is used
99
+ def create(params = {}, attributes = {})
100
+ raise ArgumentError.new("Record already exists for '#{params[:id]}'") if self.is_exist?(params[:id])
101
+ if self.validates_presence
102
+ self.validates_presence.each do |field|
103
+ raise ArgumentError.new("Missing required field '#{field}'") unless params[field]
104
+ end
105
+ end
106
+ o = self.new
107
+ o.id = params[:id].nil? ? o.next_id : params[:id]
108
+ params[:rho__id] = params[:id]
109
+ populate_model(o,params)
110
+ populate_attributes(o,attributes)
111
+ end
112
+
113
+ def load(id, params={})
114
+ return unless self.is_exist?(id)
115
+ populate_attributes(self.with_key(id),params)
116
+ end
117
+
118
+ def populate_attributes(obj,attribs)
119
+ attribs.each do |attrib,value|
120
+ obj.send "#{attrib.to_s}=".to_sym, value
121
+ end
122
+ obj
123
+ end
124
+
125
+ def validates_presence_of(*names)
126
+ self.validates_presence ||= []
127
+ names.each do |name|
128
+ self.validates_presence << name
129
+ end
130
+ end
131
+
132
+ # Creates new model instance with given id
133
+ alias_method :with_key, :new
134
+ alias_method :with_next_key, :create
135
+
136
+ # Defines marshaled rw accessor for redis string value
137
+ def field(name, type = :string)
138
+ if @fields.nil?
139
+ @fields = []
140
+ field :rho__id, :string
141
+ end
142
+ type = type.to_sym
143
+ type = :integer if type == :int
144
+
145
+ class_name = marshal_class_name(name, type)
146
+
147
+ fields << {:name => name.to_s, :type => type}
148
+ if type == :string
149
+ class_eval "def #{name}; @#{name} ||= redis[field_key('#{name}')]; end"
150
+ class_eval "def #{name}=(value); @#{name} = redis[field_key('#{name}')] = value; end"
151
+ else
152
+ class_eval "def #{name}; @#{name} ||= Marshal::#{class_name}.load(redis[field_key('#{name}')]); end"
153
+ class_eval "def #{name}=(value); @#{name} = value; redis[field_key('#{name}')] = Marshal::#{class_name}.dump(value); end"
154
+ end
155
+ end
156
+ alias_method :value, :field
157
+
158
+ # Defines accessor for redis list
159
+ def list(name, type = :string)
160
+ class_name = marshal_class_name(name, type)
161
+
162
+ fields << {:name => name.to_s, :type => :list}
163
+ class_eval "def #{name}; @#{name} ||= ListProxy.new(self.redis, field_key('#{name}'), Marshal::#{class_name}); end"
164
+ eval_writer(name)
165
+ end
166
+
167
+ # Defines accessor for redis set
168
+ def set(name, type = :string)
169
+ class_name = marshal_class_name(name, type)
170
+
171
+ fields << {:name => name.to_s, :type => :set}
172
+ class_eval "def #{name}; @#{name} ||= SetProxy.new(self.redis, field_key('#{name}'), Marshal::#{class_name}); end"
173
+ eval_writer(name)
174
+ end
175
+
176
+ def marshal_class_name(name, type)
177
+ Marshal::TYPES[type] or raise ArgumentError.new("Unknown type #{type} for field #{name}")
178
+ end
179
+
180
+ # Redefine this to change connection options
181
+ def redis
182
+ @@redis ||= Store.db
183
+ end
184
+
185
+ def fields #:nodoc:
186
+ @fields ||= []
187
+ end
188
+
189
+ protected
190
+ def eval_writer(name) #:nodoc:
191
+ class_eval <<-END
192
+ def #{name}=(value)
193
+ field = self.#{name};
194
+ if value.respond_to?(:each)
195
+ value.each {|v| field << v}
196
+ else
197
+ field << v
198
+ end
199
+ end
200
+ END
201
+ end
202
+
203
+ def populate_model(model, fields)
204
+ return model if fields.empty?
205
+ methods = model.methods
206
+ fields.each do |name,value|
207
+ model.send("#{name}=", value) if methods.include?(name.to_s)
208
+ end
209
+ model
210
+ end
211
+ end
212
+
213
+ module Marshal
214
+ TYPES = {
215
+ :string => 'String',
216
+ :integer => 'Integer',
217
+ :float => 'Float',
218
+ :datetime => 'DateTime',
219
+ :json => 'JSON',
220
+ }
221
+
222
+ class String
223
+ def self.dump(v)
224
+ v
225
+ end
226
+
227
+ def self.load(v)
228
+ v
229
+ end
230
+ end
231
+
232
+ class Integer
233
+ def self.dump(v)
234
+ v.to_s
235
+ end
236
+
237
+ def self.load(v)
238
+ v && v.to_i
239
+ end
240
+ end
241
+
242
+ class Float
243
+ def self.dump(v)
244
+ v.to_s
245
+ end
246
+
247
+ def self.load(v)
248
+ v && v.to_f
249
+ end
250
+ end
251
+
252
+ class DateTime
253
+ def self.dump(v)
254
+ v.strftime('%FT%T%z')
255
+ end
256
+
257
+ def self.load(v)
258
+ v && ::DateTime.strptime(v, '%FT%T%z')
259
+ end
260
+ end
261
+
262
+ class JSON
263
+ def self.dump(v)
264
+ ::JSON.dump(v)
265
+ end
266
+
267
+ def self.load(v)
268
+ v && ::JSON.load(v)
269
+ end
270
+ end
271
+ end
272
+
273
+
274
+
275
+ class FieldProxy #:nodoc
276
+ def initialize(redis, name, marshal)
277
+ @redis = redis
278
+ @name = name
279
+ @marshal = marshal
280
+ end
281
+
282
+ # def method_missing(method, *argv)
283
+ # translated_method = translate_method_name(method)
284
+ # raise NoMethodError.new("Method '#{method}' is not defined") unless translated_method
285
+ # @redis.send translated_method, @name, *argv
286
+ # end
287
+ #
288
+ # protected
289
+ # def translate_method_name(m)
290
+ # m
291
+ # end
292
+ end
293
+
294
+
295
+
296
+ class ListProxy < FieldProxy #:nodoc:
297
+ def <<(v)
298
+ @redis.rpush @name, @marshal.dump(v)
299
+ end
300
+ alias_method :push_tail, :<<
301
+
302
+ def push_head(v)
303
+ @redis.lpush @name, @marshal.dump(v)
304
+ end
305
+
306
+ def pop_tail
307
+ @marshal.load(@redis.rpop(@name))
308
+ end
309
+
310
+ def pop_head
311
+ @marshal.load(@redis.lpop(@name))
312
+ end
313
+
314
+ def [](from, to = nil)
315
+ if to.nil?
316
+ @marshal.load(@redis.lindex(@name, from))
317
+ else
318
+ @redis.lrange(@name, from, to).map! { |v| @marshal.load(v) }
319
+ end
320
+ end
321
+ alias_method :range, :[]
322
+
323
+ def []=(index, v)
324
+ @redis.lset(@name, index, @marshal.dump(v))
325
+ end
326
+ alias_method :set, :[]=
327
+
328
+ def include?(v)
329
+ @redis.exists(@name, @marshal.dump(v))
330
+ end
331
+
332
+ def remove(count, v)
333
+ @redis.lrem(@name, count, @marshal.dump(v))
334
+ end
335
+
336
+ # def length
337
+ # @redis.llen(@name)
338
+ # end
339
+ #
340
+ # def trim(from, to)
341
+ # @redis.ltrim(@name, from, to)
342
+ # end
343
+ #
344
+ # def to_s
345
+ # range(0, 100).join(', ')
346
+ # end
347
+ #
348
+ # protected
349
+ # def translate_method_name(m)
350
+ # COMMANDS[m]
351
+ # end
352
+ end
353
+
354
+
355
+
356
+ class SetProxy < FieldProxy #:nodoc:
357
+ # COMMANDS = {
358
+ # :intersect_store => "sinterstore",
359
+ # :union_store => "sunionstore",
360
+ # :diff_store => "sdiffstore",
361
+ # :move => "smove",
362
+ # }
363
+
364
+ def <<(v)
365
+ @redis.sadd @name, @marshal.dump(v)
366
+ end
367
+ alias_method :add, :<<
368
+
369
+ def delete(v)
370
+ @redis.srem @name, @marshal.dump(v)
371
+ end
372
+ alias_method :remove, :delete
373
+
374
+ def include?(v)
375
+ @redis.sismember @name, @marshal.dump(v)
376
+ end
377
+ alias_method :has_key?, :include?
378
+ alias_method :member?, :include?
379
+
380
+ def members
381
+ @redis.smembers(@name).map { |v| @marshal.load(v) }
382
+ end
383
+
384
+ def intersect(*keys)
385
+ @redis.sinter(@name, *keys).map { |v| @marshal.load(v) }
386
+ end
387
+
388
+ def union(*keys)
389
+ @redis.sunion(@name, *keys).map { |v| @marshal.load(v) }
390
+ end
391
+
392
+ def diff(*keys)
393
+ @redis.sdiff(@name, *keys).map { |v| @marshal.load(v) }
394
+ end
395
+
396
+ # def length
397
+ # @redis.llen(@name)
398
+ # end
399
+ #
400
+ # def to_s
401
+ # members.join(', ')
402
+ # end
403
+ #
404
+ # protected
405
+ # def translate_method_name(m)
406
+ # COMMANDS[m]
407
+ # end
408
+ end
409
+ end
410
+ end
@@ -0,0 +1,55 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ module Rhosync
4
+ class Blackberry
5
+ def self.ping(params)
6
+ begin
7
+ settings = get_config(Rhosync.base_directory)[Rhosync.environment]
8
+ host = settings[:mdsserver]
9
+ port = settings[:mdsserverport]
10
+
11
+ headers = { "X-WAP-APPLICATION-ID" => "/",
12
+ "X-RIM-PUSH-DEST-PORT" => params['device_port'],
13
+ "CONTENT-TYPE" => 'multipart/related; type="application/xml"; boundary=asdlfkjiurwghasf'}
14
+
15
+ Net::HTTP.new(host,port).start do |http|
16
+ request = Net::HTTP::Post.new('/pap',headers)
17
+ request.body = pap_message(params)
18
+ http.request(request)
19
+ end
20
+
21
+ rescue Exception => error
22
+ log "Error while sending ping: #{error}"
23
+ raise error
24
+ end
25
+ end
26
+
27
+ def self.pap_message(params)
28
+ data = "do_sync=" + (params['sources'] ? params['sources'].join(',') : "") + "\r\n"
29
+ data << "show_popup=#{params['message']}\r\n" if params['message']
30
+ data << "vibrate=#{params['vibrate']}\r\n" if params['vibrate']
31
+ post_body = <<-DESC
32
+ --asdlfkjiurwghasf
33
+ Content-Type: application/xml; charset=UTF-8
34
+
35
+ <?xml version="1.0"?>
36
+ <!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN"
37
+ "http://www.wapforum.org/DTD/pap_2.0.dtd"
38
+ [<?wap-pap-ver supported-versions="2.0"?>]>
39
+ <pap>
40
+ <push-message push-id="pushID:#{(rand * 100000000).to_i.to_s}" ppg-notify-requested-to="http://localhost:7778">
41
+
42
+ <address address-value="WAPPUSH=#{params['device_pin'].to_i.to_s(base=16).upcase}%3A100/TYPE=USER@rim.net"/>
43
+ <quality-of-service delivery-method="preferconfirmed"/>
44
+ </push-message>
45
+ </pap>
46
+ --asdlfkjiurwghasf
47
+ Content-Type: text/plain
48
+
49
+ #{data}
50
+ --asdlfkjiurwghasf--
51
+ DESC
52
+ post_body.gsub!(/\n/,"\r\n")
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,44 @@
1
+ require 'socket'
2
+ require 'openssl'
3
+ module Rhosync
4
+ class Iphone
5
+ def self.ping(params)
6
+ settings = get_config(Rhosync.base_directory)[Rhosync.environment]
7
+ cert_file = File.join(Rhosync.base_directory,settings[:iphonecertfile])
8
+ cert = File.read(cert_file) if File.exists?(cert_file)
9
+ passphrase = settings[:iphonepassphrase]
10
+ host = settings[:iphoneserver]
11
+ port = settings[:iphoneport]
12
+ begin
13
+ ssl_ctx = OpenSSL::SSL::SSLContext.new
14
+ ssl_ctx.key = OpenSSL::PKey::RSA.new(cert, passphrase)
15
+ ssl_ctx.cert = OpenSSL::X509::Certificate.new(cert)
16
+
17
+ socket = TCPSocket.new(host, port)
18
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_ctx)
19
+ ssl_socket.sync = true
20
+ ssl_socket.connect
21
+
22
+ ssl_socket.write(apn_message(params))
23
+ ssl_socket.close
24
+ socket.close
25
+ rescue SocketError => error
26
+ log "Error while sending ping: #{error}"
27
+ raise error
28
+ end
29
+ end
30
+
31
+ # Generates APNS package
32
+ def self.apn_message(params)
33
+ data = {}
34
+ data['aps'] = {}
35
+ data['aps']['alert'] = params['message'] if params['message']
36
+ data['aps']['badge'] = params['badge'].to_i if params['badge']
37
+ data['aps']['sound'] = params['sound'] if params['sound']
38
+ data['aps']['vibrate'] = params['vibrate'] if params['vibrate']
39
+ data['do_sync'] = params['sources'] if params['sources']
40
+ json = data.to_json
41
+ "\0\0 #{[params['device_pin'].delete(' ')].pack('H*')}\0#{json.length.chr}#{json}"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,2 @@
1
+ require 'rhosync/ping/iphone'
2
+ require 'rhosync/ping/blackberry'
@@ -0,0 +1,27 @@
1
+ module Rhosync
2
+ class ReadState < Model
3
+ field :refresh_time,:integer
4
+
5
+ def self.create(fields)
6
+ fields[:id] = get_id(fields)
7
+ fields.delete(:app_id)
8
+ fields.delete(:user_id)
9
+ fields.delete(:source_name)
10
+ fields[:refresh_time] ||= Time.now.to_i
11
+ super(fields,{})
12
+ end
13
+
14
+ def self.load(params)
15
+ super(get_id(params),{})
16
+ end
17
+
18
+ def self.delete(app_id)
19
+ Store.flash_data("#{class_prefix(self)}:#{app_id}:*")
20
+ end
21
+
22
+ private
23
+ def self.get_id(params)
24
+ "#{params[:app_id]}:#{params[:user_id]}:#{params[:source_name]}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,12 @@
1
+ <html>
2
+ <head>
3
+ <title>Rhosync Server</title>
4
+ </head>
5
+ <body>
6
+ <h3>Rhosync Server v<%=Rhosync::VERSION%> running...</h3>
7
+ <p><a href="/resque/">Resque</a></p>
8
+ <p><a href="/console/">Console</a></p>
9
+ <h3>Rhosync Info</h3>
10
+ TBD...
11
+ </body>
12
+ </html>