seapig-router 0.2.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3768c130c423cc69ca19d096eeda6c82b8b5358f
4
+ data.tar.gz: 77e72a3c2eea960238e86e1e213e96975796a2c8
5
+ SHA512:
6
+ metadata.gz: c931ea140f573f728241091a7cac85e619a0472629a4d982697bb423d128c2df507287fa79b7e5e095024d79d059e432e185e61fd1e4df905b9b2fa6abdd4ebf
7
+ data.tar.gz: 742b59786fa95ca5a675883d97f9fa76857858553221e908a21e521a38b6d446358fe4d9c267745c83a2e4e5e4d397508aedd7be94c5bd75fc32808f6f11b95e
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015-2017 yunta
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'jasmine'
2
+ load 'jasmine/tasks/jasmine.rake'
@@ -0,0 +1,334 @@
1
+ class @SeapigRouter
2
+
3
+
4
+ constructor: (seapig_client, options={})->
5
+ @seapig_client = seapig_client
6
+ @session_id = undefined
7
+ @mountpoint = (options.mountpoint or "/")
8
+ @default_state = (options.default or {})
9
+ @debug = options.debug
10
+ @expose = (options.expose or [])
11
+ @cast = (options.cast or (state)-> state)
12
+ @onsessionopen = options.onsessionopen
13
+
14
+ @token = (String.fromCharCode(48 + code + (if code > 9 then 7 else 0) + (if code > 35 then 6 else 0)) for code in (Math.floor(Math.random()*62) for i in [0..11])).join("")
15
+ console.log('ROUTER: Generated token: ', @token) if @debug
16
+
17
+ @state = undefined
18
+ @state_id = 1
19
+ @state_raw = { session_id: undefined, state_id: 0, state_parent: undefined, state_committed: true }
20
+ @state_valid = false
21
+
22
+ commit_scheduled_at = null
23
+ commit_timer = null
24
+ remote_state = null
25
+
26
+ priv = {}
27
+ @private = priv if options.expose_privates
28
+
29
+ session_data = @seapig_client.master('SeapigRouter::Session::'+@token+'::Data', object: { token: @token, session: @session_id, states: {}})
30
+ session_data.bump()
31
+
32
+ session_data_saved = @seapig_client.slave('SeapigRouter::Session::'+@token+'::Saved')
33
+ session_data_saved.onchange =>
34
+ return if not session_data_saved.valid
35
+ for state_id in _.keys(session_data.object.states)
36
+ delete session_data.object.states[state_id] if parseInt(state_id) < session_data_saved.object.max_state_id
37
+ if not @session_id?
38
+ @session_id = session_data_saved.object.session_id
39
+ @state.session_id = @state_raw.session_id = @session_id if @state? and not @state_raw.session_id?
40
+ console.log('ROUTER: Session opened', @session_id) if @debug
41
+ @onsessionopen(@session_id) if @onsessionopen?
42
+ console.log('ROUTER: Session saved up till:', session_data_saved.object.max_state_id) if @debug
43
+ location_update(false) if @state_valid
44
+
45
+
46
+ document.onclick = (event) =>
47
+ href = (event.target.getAttribute("href") or "")
48
+ console.log('ROUTER: A-element clicked, changing location to:', href) if @debug
49
+ return true if not (href[0] == '?')
50
+ @navigate(href)
51
+ false
52
+
53
+
54
+ window.onpopstate = (event) =>
55
+ @state_raw = JSON.parse(JSON.stringify(event.state))
56
+ @state_raw.session_id = @session_id if not @state_raw.session_id?
57
+ @state = @cast(JSON.parse(JSON.stringify(@state_raw)))
58
+ console.log('ROUTER: History navigation triggered. Going to:', event.state) if @debug
59
+ location_update(false)
60
+ @onchange(@state_raw, previous_state) if @onchange?
61
+
62
+
63
+ state_permanent = (state)=>
64
+ _.omit(state, (value, key)-> key.indexOf("_") == 0 or key == "session_id" or key == "state_id" or key == "state_parent" or key == "state_committed")
65
+
66
+
67
+ state_diff_generate = priv.state_diff_generate = (state1, state2)=>
68
+
69
+ element_diff = (diff, address, object1, object2)->
70
+ same_type = ((typeof object1 == typeof object2) and (Array.isArray(object1) == Array.isArray(object2)))
71
+ if (not object2?) or (object1? and not same_type)
72
+ diff.push ['-'+address, '-']
73
+ object1 = undefined
74
+ if Array.isArray(object2)
75
+ array_diff(diff, address+"~", object1 or [], object2)
76
+ else if typeof object2 == 'object'
77
+ object_diff(diff, address+".", object1 or {}, object2)
78
+ else if object2?
79
+ diff.push [address, object2] if object1 != object2
80
+
81
+ object_diff = (diff, address, object1, object2)->
82
+ for key in _.uniq(_.union(_.keys(object1), _.keys(object2)))
83
+ element_diff(diff, address+key, object1[key], object2[key])
84
+ diff
85
+
86
+ array_diff = (diff, address, array1, array2)->
87
+ j = 0
88
+ for element1, i in array1
89
+ if _.isEqual(element1, array2[j])
90
+ j++
91
+ else
92
+ k = j
93
+ k++ while (not _.isEqual(element1,array2[k])) and (k < array2.length)
94
+ if k == array2.length
95
+ if typeof element1 == 'object'
96
+ diff.push ["-"+address+j+"~", "-"]
97
+ else
98
+ diff.push ["-"+address+"~", element1]
99
+ else
100
+ while j < k
101
+ element_diff(diff, address+j+"~", undefined, array2[j++])
102
+ j++
103
+
104
+ while j < array2.length
105
+ element_diff(diff, address+"~", undefined, array2[j++])
106
+
107
+ object_diff([], "", state1, state2)
108
+
109
+
110
+ state_diff_apply = priv.state_diff_apply = (state, diff)=>
111
+ for entry in diff
112
+ address = entry[0]
113
+ value = entry[1]
114
+ add = (address[0] != '-')
115
+ address = address[1..-1] if address[0] == '-'
116
+ obj = state
117
+ spl = address.split('.')
118
+ for subobj,i in spl
119
+ if i < (spl.length-1)
120
+ if subobj[subobj.length-1] == '~'
121
+ if subobj.split("~")[1].length > 0
122
+ obj[parseInt(subobj.split("~")[1])] = {} if not obj[parseInt(subobj.split("~")[1])]
123
+ obj = obj[parseInt(subobj.split("~")[1])]
124
+ else
125
+ obj[subobj.split("~")[0]] = [new_obj = {}]
126
+ obj = new_obj
127
+ else
128
+ obj[subobj] = {} if not obj[subobj]?
129
+ obj = obj[subobj]
130
+ address = spl[spl.length-1]
131
+ hash = (address[address.length-1] != '~')
132
+ index = undefined
133
+ index = parseInt(address.split('~')[1]) if (not hash) and address.split("~")[1].length > 0
134
+ address = address.split("~")[0]
135
+ if add
136
+ if hash
137
+ obj[address] = value
138
+ else
139
+ if index?
140
+ (obj[address] ||= []).splice(index,0,value)
141
+ else
142
+ (obj[address] ||= []).push(value)
143
+ else
144
+ if hash
145
+ delete obj[address]
146
+ else
147
+ if index?
148
+ obj[address].splice(index,1)
149
+ else
150
+ obj[address].splice(_.indexOf(obj[address], value),1)
151
+ state
152
+
153
+
154
+ url_to_state_description = (pathname, search)=>
155
+
156
+ # URL FORMAT:
157
+ # /VERSION/SESSION_ID/STATE_ID/[EXPOSED_DIFF/][-/BUFFER_DIFF][?CHANGE_DIFF]
158
+ # VERSION - format code
159
+ # SESSION_ID
160
+ # STATE_ID - id of latest state saved on server
161
+ # EXPOSED DIFF - "pretty" part of the url, exposing selected state components for end user manipulation.
162
+ # BUFFER_DIFF - temporary section, holding the difference between STATE_ID state and current state. vanishes after current state gets saved on server.
163
+ # CHANGE_DIFF - temporary section, holding state change intended by <A> link (e.g. href="?view=users&user=10"). vanishes immediately and gets transeferred to BUFFER_DIFF.
164
+
165
+ state_description = { session_id: null, state_id: null, buffer: [], exposed: [], change: [] }
166
+
167
+ spl = pathname.split(@mountpoint)
168
+ spl.shift()
169
+ spl = (decodeURIComponent(part) for part in spl.join(@mountpoint).split('/'))
170
+
171
+ version = spl.shift()
172
+ if version == 'a'
173
+ state_description.session_id = spl.shift()
174
+ state_description.session_id = undefined if state_description.session_id == '_'
175
+ state_description.state_id = spl.shift()
176
+
177
+ if state_description.state_id?
178
+ while spl.length > 0
179
+ key = spl.shift()
180
+ break if key == '-'
181
+ component = _.find @expose, (component)-> component[1]
182
+ next if not component
183
+ state_description.exposed.push([component[0],spl.shift()])
184
+
185
+ while spl.length > 0
186
+ state_description.buffer.push([spl.shift(),spl.shift()])
187
+ else
188
+ state_description.session_id = @session_id
189
+ state_description.state_id = 0
190
+ state_description.buffer = state_diff_generate(state_permanent(@state_raw), state_permanent(@default_state))
191
+
192
+ if search.length > 1
193
+ for pair in search.split('?')[1].split('&')
194
+ decoded_pair = (decodeURIComponent(part) for part in pair.split('=',2))
195
+ state_description.change.push(decoded_pair)
196
+
197
+ console.log('ROUTER: Parsed location', state_description) if @debug
198
+ state_description
199
+
200
+
201
+ state_description_to_url = (state_description)=>
202
+ console.log('ROUTER: Calculating url for state description:', state_description) if @debug
203
+ url = @mountpoint+'a/'+(state_description.session_id or '_')+'/'+state_description.state_id
204
+ url += "/"+(encodeURIComponent(component) for component in _.flatten(state_description.exposed)).join("/") if state_description.exposed.length > 0
205
+ url += "/-/"+(encodeURIComponent(component) for component in _.flatten(state_description.buffer)).join("/") if state_description.buffer.length > 0
206
+ console.log('ROUTER: Calculated url:', url) if @debug
207
+ url
208
+
209
+
210
+ state_set_from_state_description = (state_description, defer, replace)=>
211
+
212
+ state_commit = (replace) =>
213
+ console.log("ROUTER: Committing state:",@state_raw) if @debug
214
+ @state_raw.state_committed = true
215
+ session_data.object.states[@state_raw.state_id] = state_permanent(@state_raw)
216
+ session_data.bump()
217
+ clearTimeout(commit_timer) if commit_timer
218
+ commit_scheduled_at = null
219
+ commit_timer = null
220
+ location_update(replace)
221
+
222
+ commit_needed_at = Date.now() + defer
223
+
224
+ if not @state_raw.state_committed
225
+ last_committed_state = @state_raw.state_parent
226
+ else
227
+ last_committed_state = @state_raw
228
+
229
+ console.log("ROUTER: Changing state. Commit deferred by", defer, "to be done at", commit_needed_at, " State before mutation:",last_committed_state) if @debug
230
+
231
+ previous_state = @state_raw
232
+ new_state = JSON.parse(JSON.stringify(state_permanent(@state_raw)))
233
+ new_state = state_diff_apply(new_state, state_description.buffer)
234
+ new_state = state_diff_apply(new_state, state_description.exposed)
235
+ new_state = state_diff_apply(new_state, state_description.change)
236
+ _.extend(new_state, _.pick(previous_state, (value,key)-> key.indexOf("_") == 0))
237
+
238
+ if state_diff_generate(state_permanent(last_committed_state), state_permanent(new_state)).length > 0
239
+ new_state.state_committed = false
240
+ if previous_state.state_committed
241
+ new_state.session_id = @session_id
242
+ new_state.state_id = @state_id++
243
+ new_state.state_parent = previous_state
244
+ else
245
+ new_state.session_id = previous_state.session_id
246
+ new_state.state_id = previous_state.state_id
247
+ new_state.state_parent = previous_state.state_parent
248
+ else
249
+ new_state.session_id = last_committed_state.session_id
250
+ new_state.state_id = last_committed_state.state_id
251
+ new_state.state_parent = last_committed_state.state_parent
252
+ new_state.state_committed = last_committed_state.state_committed
253
+
254
+ @filter(new_state, previous_state) if @filter?
255
+ @state_raw = new_state
256
+ @state = @cast(JSON.parse(JSON.stringify(@state_raw)))
257
+ @state_valid = true
258
+
259
+ if @state_raw.state_committed
260
+ clearTimeout(commit_timer) if commit_timer
261
+ commit_scheduled_at = null
262
+ commit_timer = null
263
+ else
264
+ if commit_needed_at <= Date.now()
265
+ state_commit(replace)
266
+ else
267
+ location_update(false)
268
+ if (not commit_scheduled_at) or (commit_needed_at < commit_scheduled_at)
269
+ console.log("ROUTER: Deferring commit by:", defer, "till", commit_needed_at) if @debug
270
+ @state_raw.state_committed = false
271
+ clearTimeout(commit_timer) if commit_timer
272
+ commit_scheduled_at = commit_needed_at
273
+ commit_timer = setTimeout((()=> state_commit(replace)), commit_scheduled_at - Date.now())
274
+
275
+ @onchange(@state_raw,previous_state) if @onchange?
276
+
277
+
278
+ state_get_as_state_description = (state)=>
279
+ last_committed_state = state
280
+ while last_committed_state.state_parent and ((not last_committed_state.session_id) or last_committed_state.session_id == @session_id) and ((session_data_saved.object.max_state_id or 0 ) < last_committed_state.state_id)
281
+ last_committed_state = last_committed_state.state_parent
282
+ console.log('ROUTER: Last shareable state:', last_committed_state) if @debug
283
+ buffer = state_diff_generate(state_permanent(last_committed_state), state_permanent(state))
284
+ exposed = ([component[1], pair[1]] for pair in state_diff_generate({}, state) when component = _.find @expose, (component)-> component[0] == pair[0])
285
+ buffer = (pair for pair in buffer when not _.find @expose, (component)-> component[0] == pair[0])
286
+ { session_id: last_committed_state.session_id, state_id: last_committed_state.state_id, exposed: exposed, buffer: buffer, change: [] }
287
+
288
+
289
+ location_update = (new_history_entry)=>
290
+ url = state_description_to_url(state_get_as_state_description(@state_raw))
291
+ console.log("ROUTER: Updating location: state:", @state_raw, ' url:', url) if @debug
292
+ if new_history_entry
293
+ window.history.pushState(@state_raw,null,url)
294
+ else
295
+ window.history.replaceState(@state_raw,null,url)
296
+
297
+
298
+ @navigate = (search, options = {})->
299
+ pathname = window.location.pathname
300
+
301
+ console.log('ROUTER: Navigating to: pathname:', pathname, ' search:', search) if @debug
302
+ state_description = url_to_state_description(pathname, search)
303
+ console.log('ROUTER: New state description:', state_description) if @debug
304
+
305
+ if remote_state?
306
+ remote_state.unlink()
307
+ remote_state = null
308
+
309
+ if state_description.session_id == @session_id or state_description.state_id == "0"
310
+ state_set_from_state_description(state_description, (options.defer or 0), !options.replace)
311
+ else
312
+ @state_valid = false
313
+ remote_state = @seapig_client.slave('SeapigRouter::Session::'+state_description.session_id+'::State::'+state_description.state_id)
314
+ remote_state.onchange ()=>
315
+ return if not remote_state.valid
316
+ console.log("ROUTER: Received remote state", remote_state.object) if @debug
317
+ @state_raw = JSON.parse(JSON.stringify(remote_state.object))
318
+ @state_raw.state_committed = true
319
+ @state_raw.session_id = state_description.session_id
320
+ @state_raw.state_id = state_description.state_id
321
+ @state_raw.state_parent = undefined
322
+ state_set_from_state_description(state_description, (options.defer or 0), !options.replace)
323
+ remote_state.unlink()
324
+ remote_state = null
325
+
326
+
327
+ @volatile = (data...)->
328
+ if data.length == 1 and typeof data[0] == 'object'
329
+ for key, value of data[0]
330
+ @state["_"+key] = value
331
+ _.extend(@state_raw, _.pick(@state, (value,key)-> key.indexOf("_") == 0))
332
+ window.history.replaceState(@state_raw,null,window.location)
333
+ else
334
+ _.object(([key, @state["_"+key]] for key in data))
@@ -0,0 +1,5 @@
1
+ class SeapigRouterSession < ActiveRecord::Base
2
+
3
+ has_many :seapig_router_session_states
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ class SeapigRouterSessionState < ActiveRecord::Base
2
+
3
+ belongs_to :seapig_router_session
4
+
5
+ end
@@ -0,0 +1,55 @@
1
+ #!/bin/env ruby
2
+
3
+ require 'slop'
4
+ require 'yaml'
5
+ require 'seapig-client'
6
+ require 'active_record'
7
+
8
+ require 'seapig-postgresql-notifier'
9
+ require 'seapig-router'
10
+
11
+
12
+
13
+ OPTIONS = Slop.parse { |o|
14
+ o.string '-c', '--connect', "Seapig server address (default: ws://127.0.0.1:3001)", default: "ws://127.0.0.1:3001"
15
+ o.string '-d', '--database-url', 'Database URL (e.g. postgres://USER:PASS@PGHOST/DBNAME)'
16
+ o.string '-e', '--environment' , 'Rails environment to use when loading database config from config/database.yml'
17
+ o.on '-h', '--help' do puts o; exit end
18
+ }
19
+
20
+ if (not OPTIONS["database-url"]) and (not File.exist?("config/database.yml")) then puts "Either -d or config/database.yml is needed"; exit end
21
+ database_config = (OPTIONS["database-url"] or YAML.load_file("config/database.yml")[(OPTIONS["environment"] or ENV["RAILS_ENV"] or "development")])
22
+ ActiveRecord::Base.establish_connection(database_config)
23
+
24
+
25
+ EM.run {
26
+
27
+ SeapigClient.new(OPTIONS["connect"],name: 'session-manager').slave('SeapigRouter::Session::*::Data').onchange { |session_data|
28
+ token = session_data["token"]
29
+ next if token != session_data.id.split('::')[2]
30
+ if not session = SeapigRouterSession.find_by(token: token)
31
+ begin
32
+ session_id = (('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a).shuffle[0..11].join('')
33
+ session = SeapigRouterSession.create!(key: session_id, token: token)
34
+ rescue ActiveRecord::RecordNotUnique
35
+ retry #FIXME: DOS
36
+ end
37
+ puts "Created new session: "+session.key+" for token: "+token
38
+ end
39
+ next if session_data["session_id"] and session.key != session_data["session_id"]
40
+
41
+ print "Saving session "+session.key+" states: "
42
+ max_state = session.seapig_router_session_states.order("state_id DESC").first
43
+ max_state_id = (max_state and max_state.state_id or -1)
44
+ session_data['states'].each_pair { |id, state|
45
+ if id.to_i > max_state_id
46
+ print ' '+id
47
+ SeapigRouterSessionState.create!(seapig_router_session_id: session.id, state_id: id, state: state)
48
+ end
49
+ }
50
+ puts
51
+ SeapigDependency.bump("SeapigRouter::Session::"+token)
52
+ SeapigDependency.bump("SeapigRouter::Session::"+session.key)
53
+ }
54
+
55
+ }
@@ -0,0 +1,9 @@
1
+ class CreateSeapigRouterSessions < ActiveRecord::Migration
2
+ def change
3
+ create_table :seapig_router_sessions do |t|
4
+ t.text :key
5
+ t.timestamps null: false
6
+ end
7
+ add_index :seapig_router_sessions, :key, unique: true
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ class CreateSeapigRouterSessionStates < ActiveRecord::Migration
2
+ def change
3
+ create_table :seapig_router_session_states do |t|
4
+ t.integer :seapig_router_session_id
5
+ t.integer :state_id
6
+ t.jsonb :state
7
+
8
+ t.timestamps null: false
9
+ end
10
+ add_index :seapig_router_session_states, [:seapig_router_session_id,:state_id], unique: true, name: "seapig_router_session_states_index_1"
11
+
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ class AddTokenToSeapigSessions < ActiveRecord::Migration
2
+ def change
3
+ add_column :seapig_router_sessions, :token, :text
4
+ add_index :seapig_router_sessions, :token, unique: true, name: "seapig_router_sessions_token_index"
5
+ add_index :seapig_router_sessions, [:key,:token], unique: true, name: "seapig_router_sessions_key_token_index"
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ require "seapig-router/engine"
2
+ require_relative '../app/models/seapig_router_session.rb'
3
+ require_relative '../app/models/seapig_router_session_state.rb'
4
+
5
+ module SeapigRouter
6
+ end
@@ -0,0 +1,6 @@
1
+ if defined? Rails
2
+ module SeapigRouter
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module SeapigRouter
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,20 @@
1
+ class SeapigRouterSessionSaved < Producer
2
+
3
+ @patterns = [ 'SeapigRouter::Session::*::Saved' ]
4
+
5
+
6
+ def self.produce(seapig_object_id)
7
+ seapig_object_id =~ /SeapigRouter::Session::([^\:]+)::Saved/
8
+ token = $1
9
+ version = SeapigDependency.versions('SeapigRouter::Session::'+token)
10
+ session = SeapigRouterSession.find_by(token: token)
11
+ return [false, version] if not session
12
+ max_state = session.seapig_router_session_states.select("state_id").order("state_id DESC").first
13
+ data = {
14
+ session_id: session.key,
15
+ max_state_id: (max_state and max_state.state_id or -1)
16
+ }
17
+ [data, version]
18
+ end
19
+
20
+ end
@@ -0,0 +1,19 @@
1
+ class SeapigRouterSessionStateProducer < Producer
2
+
3
+ @patterns = [ 'SeapigRouter::Session::*::State::*' ]
4
+
5
+
6
+ def self.produce(seapig_object_id)
7
+ seapig_object_id =~ /SeapigRouter::Session::([^\:]+)::State::([^\:]+)/
8
+ session_key = $1
9
+ state_id = $2.to_i
10
+ version = Time.new.to_f
11
+ session = SeapigRouterSession.find_by(key: session_key)
12
+ return [false, SeapigDependency.versions('SeapigRouter::Session::'+session_key)] if not session
13
+ state = SeapigRouterSessionState.find_by(seapig_router_session_id: session.id, state_id: state_id)
14
+ return [false, SeapigDependency.versions('SeapigRouter::Session::'+session_key)] if not state
15
+ data = state.state
16
+ [data, version]
17
+ end
18
+
19
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seapig-router
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - yunta
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: seapig-client-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: seapig-postgresql-notifier
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.2.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: pg
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: meh
84
+ email:
85
+ - maciej.blomberg@mikoton.com
86
+ executables:
87
+ - seapig-router-session-manager
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - MIT-LICENSE
92
+ - Rakefile
93
+ - app/assets/javascripts/seapig/seapig-router.js.coffee
94
+ - app/models/seapig_router_session.rb
95
+ - app/models/seapig_router_session_state.rb
96
+ - bin/seapig-router-session-manager
97
+ - db/migrate/20151221110834_create_seapig_router_sessions.rb
98
+ - db/migrate/20151221111628_create_seapig_router_session_states.rb
99
+ - db/migrate/20161231183822_add_token_to_seapig_sessions.rb
100
+ - lib/seapig-router.rb
101
+ - lib/seapig-router/engine.rb
102
+ - lib/seapig-router/version.rb
103
+ - lib/seapigs/seapig_router_saved_session.rb
104
+ - lib/seapigs/seapig_router_session_state.rb
105
+ homepage: https://github.com/yunta-mb/seapig-rails
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.5.2
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: Transient object synchronization lib - rails
129
+ test_files: []