seapig-rails 0.0.6 → 0.0.7
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 +4 -4
- data/app/assets/javascripts/seapig/seapig-binding.js.coffee +153 -0
- data/app/assets/javascripts/seapig/seapig-client.js.coffee +1 -0
- data/app/assets/javascripts/seapig/seapig-router.js.coffee +94 -53
- data/app/models/seapig_dependency.rb +25 -0
- data/app/models/seapig_router_session.rb +0 -3
- data/app/models/seapig_router_session_state.rb +0 -2
- data/bin/seapig-notifier +15 -29
- data/bin/seapig-session-saver +9 -6
- data/db/migrate/20151228202111_create_seapig_versions.rb +18 -0
- data/lib/seapig/version.rb +1 -1
- data/lib/seapig-rails.rb +0 -1
- data/lib/seapigs/seapig_router_saved_session.rb +2 -3
- data/lib/seapigs/seapig_router_session_state.rb +2 -2
- metadata +5 -3
- data/lib/seapig/acts_as_seapig_dependency.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42061dcf4ac1f6917849a446a9c7c172d32410ab
|
4
|
+
data.tar.gz: 9e4b9e713cfe8beb6c219b488bb561df4e8a0af2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00424c408f4db3d6a4ff1b9e609b70bc44518578013ac1af18cb363439f1462621b67f7e6527536e7ded8314dd40ce6fc4b4bc6231fddf2910e6d5db6113a6b7
|
7
|
+
data.tar.gz: b905c978f13c69f34395b5b80dca458a59424140370f54c57866f911a9bc9f95518fa72a2427b23e5a10e14d6c217c7726ea71a6209eab563b8151f69223c591
|
@@ -0,0 +1,153 @@
|
|
1
|
+
@e = (content)->
|
2
|
+
content.__seapig_binding_element__ = {
|
3
|
+
}
|
4
|
+
content
|
5
|
+
|
6
|
+
|
7
|
+
class @SeapigBinding
|
8
|
+
|
9
|
+
|
10
|
+
constructor: (seapig_server, options = {})->
|
11
|
+
@seapig_server = seapig_server
|
12
|
+
@debug = options.debug
|
13
|
+
@view(options.view) if options.view
|
14
|
+
@onchange = options.onchange
|
15
|
+
@valid = false
|
16
|
+
@initialized = false
|
17
|
+
@object = false
|
18
|
+
@object_id = null
|
19
|
+
@elements = null
|
20
|
+
@shadow = { __seapig_binding_element__: {state: {},conflict: {},updated_at: {}}}
|
21
|
+
@selector = (data) -> data
|
22
|
+
@model(options.model) if options.model?
|
23
|
+
|
24
|
+
state: (element)->
|
25
|
+
|
26
|
+
view: (view)->
|
27
|
+
$(document).on('click',view+' .seapig-binding-element-delete', (event) =>
|
28
|
+
console.log('BINDING: A-element clicked.',event) if @debug
|
29
|
+
element = @element_find(event.target)
|
30
|
+
@element_remove(element[0],element[1],$(dom_element).hasClass('seapig-bindind-autosave'))
|
31
|
+
false
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
#FIXME: OOize all element_* methods
|
36
|
+
|
37
|
+
element_remove: (parent,id,save)->
|
38
|
+
console.log("removing", parent, id) if @debug
|
39
|
+
|
40
|
+
element_find: (dom_element)->
|
41
|
+
path = []
|
42
|
+
while dom_element
|
43
|
+
id = $(dom_element).attr('data-seapig-binding-element')
|
44
|
+
path.push(id) if id
|
45
|
+
dom_element = dom_element.parentElement
|
46
|
+
path = path.reverse()
|
47
|
+
id = path.pop()
|
48
|
+
parent = @elements
|
49
|
+
for step in path
|
50
|
+
parent = parent[step]
|
51
|
+
[parent, id]
|
52
|
+
|
53
|
+
|
54
|
+
update_element: (elements, key, shadows, shadow_key, element, remote) ->
|
55
|
+
if typeof(remote) == "object"
|
56
|
+
if typeof(remote) == "undefined" #delete
|
57
|
+
delete elements[key]
|
58
|
+
delete shadows[shadow_key]
|
59
|
+
else
|
60
|
+
if (element? != remote?) or (typeof(element) != typeof(remote)) or (Array.isArray(element) != Array.isArray(remote)) #(re-)create
|
61
|
+
element = if remote == null then null else if Array.isArray(remote) then [] else {}
|
62
|
+
shadows[shadow_key] = { __seapig_binding_element__: {state: {},conflict: {},updated_at: {}}}
|
63
|
+
elements[key] = element
|
64
|
+
@update(elements[key],shadows[shadow_key],remote) if element? #update
|
65
|
+
else
|
66
|
+
if typeof(remote) == "undefined" #delete
|
67
|
+
delete elements[key]
|
68
|
+
delete shadows[shadow_key]
|
69
|
+
else #update
|
70
|
+
elements[key] = remote
|
71
|
+
if element != remote
|
72
|
+
shadows[shadow_key] ||= { __seapig_binding_element__: {state: {},conflict: {},updated_at: {}}}
|
73
|
+
shadows[shadow_key].__seapig_binding_element__.updated_at[key] = new Date()
|
74
|
+
|
75
|
+
|
76
|
+
update: (elements, shadow, remotes)->
|
77
|
+
throw "wut? a vampaya?" if not shadow?
|
78
|
+
console.log("updating",elements,shadow,remotes) if @debug
|
79
|
+
|
80
|
+
|
81
|
+
if Array.isArray(elements)
|
82
|
+
console.log('array') if @debug
|
83
|
+
elements_by_id = _.object(([(e? and e.id or i), e] for e,i in elements))
|
84
|
+
remotes_by_id = _.object(([(e? and e.id or i), e] for e,i in remotes))
|
85
|
+
shadow_shadow = _.object([k,v] for k,v of shadow)
|
86
|
+
console.log("elements_by_id, remotes_by_id", elements_by_id, remotes_by_id ) if @debug
|
87
|
+
|
88
|
+
added_elements = _.difference(_.keys(remotes_by_id),_.keys(elements_by_id))
|
89
|
+
removed_elements = _.difference(_.keys(elements_by_id),_.keys(remotes_by_id))
|
90
|
+
console.log("added", added_elements) if @debug
|
91
|
+
console.log("removed", removed_elements) if @debug
|
92
|
+
elements.length = 0
|
93
|
+
shadow.length = 0
|
94
|
+
for remote_element,i in remotes
|
95
|
+
id = (remote_element? and remote_element.id or i)
|
96
|
+
element = elements_by_id[id]
|
97
|
+
console.log('adding',remote_element,id,element) if @debug
|
98
|
+
@update_element(elements,i,shadow,id,element,remote_element)
|
99
|
+
console.log(elements) if @debug
|
100
|
+
|
101
|
+
else
|
102
|
+
console.log('object') if @debug
|
103
|
+
added_elements = _.difference(_.keys(remotes),_.keys(elements))
|
104
|
+
common_elements = _.intersection(_.keys(remotes),_.keys(elements))
|
105
|
+
removed_elements = _.difference(_.keys(elements),_.keys(remotes))
|
106
|
+
console.log("added", added_elements) if @debug
|
107
|
+
console.log("common", common_elements) if @debug
|
108
|
+
console.log("removed", removed_elements) if @debug
|
109
|
+
|
110
|
+
for element in added_elements
|
111
|
+
@update_element(elements,element,shadow,element,elements[element],remotes[element])
|
112
|
+
|
113
|
+
for element in removed_elements
|
114
|
+
switch shadow.__seapig_binding_element__.state[element]
|
115
|
+
when 'clean', undefined
|
116
|
+
@update_element(elements,element,shadow,element,elements[element],remotes[element])
|
117
|
+
else
|
118
|
+
console.log('filth! 1')
|
119
|
+
|
120
|
+
for element in common_elements
|
121
|
+
switch shadow.__seapig_binding_element__.state[element]
|
122
|
+
when 'clean', undefined
|
123
|
+
@update_element(elements,element,shadow,element,elements[element],remotes[element])
|
124
|
+
else
|
125
|
+
console.log('filth! 2')
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
model: (object_id)->
|
130
|
+
return if object_id == @object_id
|
131
|
+
@object_id = object_id
|
132
|
+
|
133
|
+
if @object
|
134
|
+
@object.unlink()
|
135
|
+
@valid = false
|
136
|
+
@initialized = false
|
137
|
+
|
138
|
+
if @object_id
|
139
|
+
@object = @seapig_server.slave(@object_id)
|
140
|
+
@object.onchange = ()=>
|
141
|
+
if @object.valid
|
142
|
+
console.log('BINDING: Data update received.') if @debug
|
143
|
+
new_elements = @selector(JSON.parse(JSON.stringify(@object.object)))
|
144
|
+
@elements ||= (if Array.isArray(new_elements) then [] else {})
|
145
|
+
@shadow ||= (if Array.isArray(new_elements) then [] else {})
|
146
|
+
@update(@elements,@shadow,new_elements)
|
147
|
+
@initialized = true
|
148
|
+
console.log(@elements) if @debug
|
149
|
+
@valid = @object.valid
|
150
|
+
@onchange() if @onchange
|
151
|
+
@data = @object.object
|
152
|
+
|
153
|
+
@onchange() if @onchange
|
@@ -1,22 +1,26 @@
|
|
1
1
|
class @SeapigRouter
|
2
2
|
|
3
3
|
|
4
|
-
constructor: (seapig_server, session_id, initial_search, debug = false)->
|
4
|
+
constructor: (seapig_server, session_id, mountpoint, initial_search, debug = false)->
|
5
5
|
@seapig_server = seapig_server
|
6
6
|
@session_id = session_id
|
7
|
+
@mountpoint = mountpoint
|
7
8
|
@debug = debug
|
8
9
|
@initial_search = initial_search
|
9
10
|
|
10
11
|
@state = {session_id: @session_id, id: 0}
|
12
|
+
@volatile = {}
|
11
13
|
|
12
14
|
@session_data = @seapig_server.master('web-session-data-'+@session_id)
|
13
15
|
@session_data.object.states = [ @state ]
|
14
16
|
@session_data.sequence = 1
|
15
17
|
@session_data.bases = {}
|
18
|
+
@session_data.diffs = {}
|
16
19
|
@session_data.changed()
|
17
20
|
|
18
21
|
@session_data_saved = @seapig_server.slave('web-session-saved-'+@session_id)
|
19
22
|
@session_data_saved.onchange = ()=>
|
23
|
+
return if not @session_data_saved.valid
|
20
24
|
while @session_data.object.states[0]? and @session_data.object.states[0].id < @session_data_saved.object.max_state_id
|
21
25
|
@session_data.object.states.shift()
|
22
26
|
console.log('Session saved, updating url:',@current_url()) if @debug
|
@@ -24,7 +28,6 @@ class @SeapigRouter
|
|
24
28
|
window.history.replaceState(@state,null,@current_url()) if @state_valid
|
25
29
|
@replacing_state = false
|
26
30
|
|
27
|
-
|
28
31
|
@replacing_state = false
|
29
32
|
@state_valid = false
|
30
33
|
|
@@ -37,77 +40,111 @@ class @SeapigRouter
|
|
37
40
|
)
|
38
41
|
|
39
42
|
window.onpopstate = (data) =>
|
43
|
+
previous_state = JSON.parse(JSON.stringify(@state))
|
40
44
|
@state = data.state
|
41
|
-
@
|
42
|
-
|
45
|
+
@update_location()
|
46
|
+
@onstatechange(@state,previous_state) if @onstatechange?
|
43
47
|
|
44
48
|
|
45
|
-
|
46
|
-
|
47
|
-
console.log('ROUTER: Location changed to: pathname:', window.location.pathname, ' search:', window.location.search) if @debug
|
48
|
-
|
49
|
-
spl = window.location.pathname.split('/')
|
49
|
+
url_to_diff: (pathname, search)->
|
50
|
+
spl = pathname.split(@mountpoint)
|
50
51
|
spl.shift()
|
52
|
+
spl = spl.join(@mountpoint).split('/')
|
51
53
|
if spl.shift() == 'a'
|
52
54
|
path_session_id = spl.shift()
|
53
55
|
path_state_id = spl.shift()
|
54
56
|
if not path_state_id
|
55
|
-
|
56
|
-
return @location_changed()
|
57
|
+
return { replace: @mountpoint+'a/'+@session_id+'/0'+window.location.search }
|
57
58
|
else
|
58
|
-
|
59
|
-
return @location_changed()
|
59
|
+
return { replace: @mountpoint+'a/'+@session_id+'/0?'+(@initial_search.replace(/^\?/,'')+window.location.search.replace(/^\?/,'&')).replace(/^&/,'') }
|
60
60
|
|
61
61
|
total_diff = []
|
62
62
|
partial_diff = []
|
63
63
|
while spl.length > 0
|
64
64
|
total_diff.push([spl.shift(),spl.shift()])
|
65
|
-
if
|
66
|
-
for pair in
|
65
|
+
if search.length > 1
|
66
|
+
for pair in search.split('?')[1].split('&')
|
67
67
|
total_diff.push(pair.split('=',2))
|
68
68
|
partial_diff.push(pair.split('=',2))
|
69
|
+
|
69
70
|
console.log('Parsed location: session_id:',path_session_id,' partial_diff:', partial_diff) if @debug
|
70
71
|
|
71
|
-
|
72
|
-
|
72
|
+
{ total: total_diff, partial: partial_diff, session_id: path_session_id, state_id: path_state_id }
|
73
|
+
|
74
|
+
|
75
|
+
location_changed: () ->
|
76
|
+
return if @replacing_state
|
77
|
+
console.log('ROUTER: Location changed to: pathname:', window.location.pathname, ' search:', window.location.search) if @debug
|
78
|
+
|
79
|
+
diff = @url_to_diff(window.location.pathname,window.location.search)
|
80
|
+
if diff.replace?
|
81
|
+
console.log('ROUTER: Invalid url, replacing with:', diff.replace) if @debug
|
82
|
+
window.history.replaceState(@state,null,diff.replace)
|
83
|
+
return @location_changed()
|
84
|
+
|
85
|
+
if diff.session_id == @session_id
|
86
|
+
@state_change(diff.partial)
|
73
87
|
else
|
74
88
|
if @remote_state?
|
75
|
-
@state_change_to_remote(
|
89
|
+
@state_change_to_remote(diff.total) #oaueia
|
76
90
|
else
|
77
91
|
@state_valid = false
|
78
|
-
if
|
79
|
-
@
|
80
|
-
@
|
92
|
+
if diff.state_id == '0'
|
93
|
+
@state = {session_id: diff.session_id, id: 0}
|
94
|
+
@state_change(diff.total)
|
81
95
|
else
|
82
|
-
@remote_state = @seapig_server.slave('web-session-state-'+
|
83
|
-
@remote_state.onchange = ()=>
|
96
|
+
@remote_state = @seapig_server.slave('web-session-state-'+diff.session_id+':'+diff.state_id)
|
97
|
+
@remote_state.onchange = ()=>
|
98
|
+
return if not @remote_state.valid
|
99
|
+
@state = _.clone(@remote_state.object)
|
100
|
+
@state_change(diff.total)
|
101
|
+
@remote_state.unlink()
|
102
|
+
@remote_state = null
|
103
|
+
|
104
|
+
|
105
|
+
state_commit: () ->
|
106
|
+
if @state.uncommitted
|
107
|
+
console.log("Deferred commit") if @debug
|
108
|
+
delete @state.uncommitted
|
109
|
+
@session_data.object.states.push(@state)
|
110
|
+
@session_data.changed()
|
111
|
+
clearTimeout(@commit_timer) if @commit_timer
|
112
|
+
@commit_at = null
|
113
|
+
@commit_timer = null
|
114
|
+
@update_location()
|
84
115
|
|
85
116
|
|
86
|
-
|
87
|
-
|
117
|
+
state_change: (diff,defer = 0) ->
|
118
|
+
commit_at = Date.now() + defer
|
119
|
+
previous_state = JSON.parse(JSON.stringify(@state))
|
88
120
|
if diff.length > 0
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
121
|
+
console.log("Applying change at:", defer, commit_at,"to",@state) if @debug
|
122
|
+
next_state = @state
|
123
|
+
if not @state.uncommitted?
|
124
|
+
base_state = @state
|
125
|
+
next_state = _.clone(@state)
|
126
|
+
next_state.session_id = @session_id
|
127
|
+
next_state.id = @session_data.sequence++
|
128
|
+
@session_data.bases[next_state.id] = base_state
|
129
|
+
@session_data.diffs[next_state.id] = []
|
130
|
+
next_state = @state_diff_apply(next_state, diff)
|
131
|
+
console.log("Pre-filter next-state", next_state)
|
132
|
+
@statefilter(next_state,previous_state) if @statefilter?
|
133
|
+
console.log("Post-filter next-state", next_state)
|
134
|
+
@state = next_state
|
135
|
+
@session_data.diffs[@state.id] = @session_data.diffs[@state.id].concat(diff)
|
136
|
+
if commit_at <= Date.now()
|
137
|
+
@state_commit()
|
138
|
+
else
|
139
|
+
@state.uncommitted = true
|
140
|
+
if (not @commit_at) or (commit_at < @commit_at)
|
141
|
+
console.log("Deferring commit by,till:", commit_at - Date.now(), commit_at) if @debug
|
142
|
+
clearTimeout(@commit_timer) if @commit_timer
|
143
|
+
@commit_at = commit_at
|
144
|
+
@commit_timer = setTimeout((()=> @state_commit()), @commit_at - Date.now())
|
95
145
|
|
96
|
-
state_change: (diff) ->
|
97
|
-
base_state = @state
|
98
|
-
@state = @state_diff_apply(_.clone(@state), diff)
|
99
|
-
@state.diff = diff
|
100
|
-
@statefilter(@state) if @statefilter?
|
101
|
-
@state.session_id = @session_id
|
102
|
-
@state.id = @session_data.sequence++
|
103
|
-
@session_data.bases[@state.id] = base_state
|
104
|
-
@session_data.object.states.push(@state)
|
105
|
-
@session_data.changed()
|
106
|
-
if @remote_state?
|
107
|
-
@remote_state.unlink() if @remote_state.object.id > 0
|
108
|
-
@remote_state = null
|
109
146
|
@state_valid = true
|
110
|
-
@
|
147
|
+
@onstatechange(@state,previous_state) if @onstatechange?
|
111
148
|
|
112
149
|
|
113
150
|
state_diff_apply: (state, diff)->
|
@@ -128,12 +165,12 @@ class @SeapigRouter
|
|
128
165
|
if hash
|
129
166
|
obj[spl[spl.length-1]] = value
|
130
167
|
else
|
131
|
-
obj[spl[spl.length-1]].push(value)
|
168
|
+
(obj[spl[spl.length-1]] ||= []).push(value)
|
132
169
|
else
|
133
170
|
if hash
|
134
171
|
delete obj[spl[spl.length-1]]
|
135
172
|
else
|
136
|
-
|
173
|
+
obj[spl[spl.length-1]].splice(_.indexOf(obj[spl[spl.length-1]], value),1)
|
137
174
|
state
|
138
175
|
|
139
176
|
|
@@ -151,17 +188,21 @@ class @SeapigRouter
|
|
151
188
|
path_overlay = ""
|
152
189
|
for state in chain
|
153
190
|
console.log('-',state) if @debug
|
154
|
-
path_overlay += @state_diff_to_path(state.
|
155
|
-
|
156
|
-
console.log('Calculated url:','/a/'+base_state.session_id+'/'+base_state.id+path_overlay) if @debug
|
157
|
-
'/a/'+base_state.session_id+'/'+base_state.id+path_overlay
|
191
|
+
path_overlay += @state_diff_to_path(@session_data.diffs[state.id])
|
158
192
|
|
193
|
+
console.log('Calculated url:',@mountpoint+'a/'+base_state.session_id+'/'+base_state.id+path_overlay) if @debug
|
194
|
+
@mountpoint+'a/'+base_state.session_id+'/'+base_state.id+path_overlay
|
159
195
|
|
160
|
-
state_changed: () ->
|
161
196
|
|
197
|
+
update_location: () ->
|
162
198
|
console.log("ROUTER: State changed to: state:", @state, ' url:', @current_url()) if @debug
|
163
199
|
@replacing_state = true
|
164
200
|
window.history.replaceState(@state,null,@current_url())
|
165
201
|
@replacing_state = false
|
166
202
|
|
167
|
-
|
203
|
+
|
204
|
+
stealth_change: (query, defer = 1000) ->
|
205
|
+
[pathname, search] = query.split("?")
|
206
|
+
pathname = window.location.pathname if pathname.length == 0
|
207
|
+
diff = @url_to_diff(pathname,"?"+(search or ""))
|
208
|
+
@state_change(diff.partial,defer)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class SeapigDependency < ActiveRecord::Base
|
2
|
+
|
3
|
+
def self.bump(*names) #FIXME: mass upsert / PG 9.5
|
4
|
+
self.transaction {
|
5
|
+
ret = names.map { |name|
|
6
|
+
value = self.find_by_sql(["UPDATE seapig_dependencies SET current_version = nextval('seapig_dependency_version_seq'), updated_at = now() WHERE name = ? RETURNING current_version", name])
|
7
|
+
value = self.find_by_sql(["INSERT INTO seapig_dependencies(name, current_version, reported_version, created_at, updated_at) VALUES (?,nextval('seapig_dependency_version_seq'),0,now(),now()) RETURNING current_version",name]) if value.size == 0
|
8
|
+
value[0].current_version
|
9
|
+
}
|
10
|
+
connection.instance_variable_get(:@connection).exec("NOTIFY seapig_dependency_changed")
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def self.version(name)
|
16
|
+
self.versions(name)[name]
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def self.versions(*names)
|
21
|
+
Hash[*self.find_by_sql(["SELECT names.name, COALESCE(sd.current_version,0) AS current_version FROM (SELECT unnest(ARRAY[?]) AS name) AS names LEFT OUTER JOIN seapig_dependencies AS sd ON names.name = sd.name", names]).map { |name| [name.name,name.current_version] }.flatten]
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
end
|
data/bin/seapig-notifier
CHANGED
@@ -1,36 +1,25 @@
|
|
1
1
|
#!/bin/env ruby
|
2
2
|
|
3
|
-
ENV['RAILS_ENV'] = 'production'
|
4
3
|
require './config/environment.rb'
|
5
4
|
|
6
5
|
require 'websocket-eventmachine-client'
|
7
6
|
require 'json'
|
8
7
|
|
9
|
-
notifiers = Hash[*ActiveRecord::Base.descendants.select { |cls| cls.respond_to?('seapig_dependency_version') }.map { |notifier| [notifier.name,notifier] }.flatten ]
|
10
8
|
|
11
|
-
|
12
|
-
notifiers.keys.each { |notifier| puts " "+notifier }
|
13
|
-
puts
|
14
|
-
|
15
|
-
$last_versions = {}
|
16
|
-
$payloads = Queue.new
|
9
|
+
#ActiveRecord::Base.logger = Logger.new(STDERR)
|
17
10
|
|
18
11
|
EM.run {
|
19
12
|
|
20
13
|
socket = WebSocket::EventMachine::Client.connect(uri: ARGV[0])
|
21
|
-
|
14
|
+
connected = false
|
22
15
|
|
23
16
|
on_database_change = Proc.new {
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
#socket.send(JSON.dump(action: 'object-update', id: notifier_name, version: version))
|
31
|
-
socket.send(JSON.dump(action: 'object-patch', id: notifier_name, new_version: version, old_version: 0))
|
32
|
-
$last_versions[notifier_name] = version
|
33
|
-
end
|
17
|
+
next if not connected
|
18
|
+
SeapigDependency.where("current_version != reported_version").each { |seapig_dependency|
|
19
|
+
puts "Dependency version changed: %30s:%-10s"%[seapig_dependency.name,seapig_dependency.current_version]
|
20
|
+
socket.send(JSON.dump(action: 'object-patch', id: seapig_dependency.name, new_version: seapig_dependency.current_version, old_version: 0))
|
21
|
+
seapig_dependency.reported_version = seapig_dependency.current_version
|
22
|
+
seapig_dependency.save!
|
34
23
|
}
|
35
24
|
}
|
36
25
|
|
@@ -43,29 +32,26 @@ EM.run {
|
|
43
32
|
connection.exec("LISTEN seapig_dependency_changed")
|
44
33
|
loop {
|
45
34
|
connection.wait_for_notify { |channel, pid, payloads|
|
46
|
-
puts "Got notification: channel="+channel+", pid="+pid.inspect+", payload="+payloads.inspect
|
47
|
-
payloads.split(",").each { |payload| $payloads << payload }
|
35
|
+
#puts "Got notification: channel="+channel+", pid="+pid.inspect+", payload="+payloads.inspect
|
48
36
|
EM.schedule(on_database_change)
|
49
37
|
}
|
50
38
|
}
|
51
39
|
}
|
52
40
|
}
|
41
|
+
connected = true
|
53
42
|
EM.schedule on_database_change
|
54
43
|
}
|
55
44
|
|
56
|
-
|
45
|
+
|
57
46
|
socket.onclose { |code, reason|
|
58
47
|
EM.stop
|
59
48
|
}
|
60
49
|
|
61
50
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
EM.add_periodic_timer(1) {
|
68
|
-
socket.send(JSON.dump(action: 'object-patch', id: 'Second', new_version: Time.new.to_i, old_version: 0))
|
51
|
+
(ARGV[1] or "").split(',').each { |interval|
|
52
|
+
EM.add_periodic_timer(interval.to_i) {
|
53
|
+
socket.send(JSON.dump(action: 'object-patch', id: 'Seconds#'+interval, new_version: Time.new.to_i/interval.to_i, old_version: 0))
|
54
|
+
}
|
69
55
|
}
|
70
56
|
}
|
71
57
|
|
data/bin/seapig-session-saver
CHANGED
@@ -11,19 +11,22 @@ EM.run {
|
|
11
11
|
SeapigServer.new(ARGV[0],name: 'session-saver').slave('web-session-data-*').onchange { |session_data|
|
12
12
|
next if session_data.destroyed
|
13
13
|
session_key = session_data.object_id
|
14
|
-
p session_key
|
15
14
|
session = SeapigRouterSession.find_by(key: session_key.split('-',4)[3])
|
16
|
-
|
15
|
+
if not session
|
16
|
+
puts "Ignoring unknown session: "+session_key
|
17
|
+
next
|
18
|
+
end
|
19
|
+
print "Saving session: "+session_key+" states: "
|
17
20
|
max_state = session.seapig_router_session_states.order("state_id DESC").first
|
18
21
|
max_state_id = (max_state and max_state.state_id or -1)
|
19
|
-
p max_state, session_data['states'].map { |s| s['id'] }
|
20
22
|
session_data['states'].each { |state|
|
21
|
-
if state['id'] > max_state_id
|
22
|
-
|
23
|
+
if state['id'] > max_state_id
|
24
|
+
print ' '+state['id'].inspect
|
23
25
|
SeapigRouterSessionState.create!(seapig_router_session_id: session.id, state_id: state['id'], state: state)
|
24
26
|
end
|
25
27
|
}
|
26
|
-
|
28
|
+
puts
|
29
|
+
SeapigDependency.bump("SeapigRouterSessionState#"+session.key)
|
27
30
|
}
|
28
31
|
|
29
32
|
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateSeapigVersions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :seapig_dependencies do |t|
|
4
|
+
t.text :name
|
5
|
+
t.bigint :current_version
|
6
|
+
t.bigint :reported_version
|
7
|
+
|
8
|
+
t.timestamps null: false
|
9
|
+
end
|
10
|
+
|
11
|
+
execute 'CREATE INDEX ON seapig_dependencies(name,current_version)'
|
12
|
+
execute 'CREATE INDEX ON seapig_dependencies((current_version != reported_version)) WHERE current_version != reported_version'
|
13
|
+
execute 'CREATE SEQUENCE seapig_dependency_version_seq OWNED BY seapig_dependencies.current_version'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# insert into seapig_dependencies (name,current_version,reported_version,created_at,updated_at) select 'reported' || generate_series, generate_series, generate_series, now(), now() from generate_series(1,1000000);
|
18
|
+
# insert into seapig_dependencies (name,current_version,reported_version,created_at,updated_at) select 'not-reported' || generate_series, generate_series, generate_series - 1 , now(), now() from generate_series(1,1000);
|
data/lib/seapig/version.rb
CHANGED
data/lib/seapig-rails.rb
CHANGED
@@ -8,10 +8,9 @@ class SeapigRouterSessionSaved < Producer
|
|
8
8
|
def self.produce(object_id)
|
9
9
|
object_id =~ /web-session-saved-([^-]+)/
|
10
10
|
session_key = $1
|
11
|
-
version =
|
12
|
-
SeapigRouterSessionState: SeapigRouterSessionState.seapig_dependency_version
|
13
|
-
}
|
11
|
+
version = SeapigDependency.versions('SeapigRouterSessionState#'+session_key)
|
14
12
|
session = SeapigRouterSession.find_by(key: session_key)
|
13
|
+
return [false, version] if not session
|
15
14
|
max_state = session.seapig_router_session_states.order("state_id DESC").first
|
16
15
|
data = {
|
17
16
|
max_state_id: (max_state and max_state.state_id or -1)
|
@@ -10,10 +10,10 @@ class SeapigRouterSessionStateProducer < Producer
|
|
10
10
|
session_key = $1
|
11
11
|
state_id = $2.to_i
|
12
12
|
version = Time.new.to_f
|
13
|
-
p session_key, object_id
|
14
13
|
session = SeapigRouterSession.find_by(key: session_key)
|
14
|
+
return [false, SeapigDependency.versions('SeapigRouterSessionState#'+session_key)] if not session
|
15
15
|
state = SeapigRouterSessionState.find_by(seapig_router_session_id: session.id, state_id: state_id)
|
16
|
-
return [false,
|
16
|
+
return [false, SeapigDependency.versions('SeapigRouterSessionState#'+session_key)] if not state
|
17
17
|
data = state.state
|
18
18
|
[data, version]
|
19
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: seapig-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yunta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -78,8 +78,10 @@ files:
|
|
78
78
|
- MIT-LICENSE
|
79
79
|
- README.rdoc
|
80
80
|
- Rakefile
|
81
|
+
- app/assets/javascripts/seapig/seapig-binding.js.coffee
|
81
82
|
- app/assets/javascripts/seapig/seapig-client.js.coffee
|
82
83
|
- app/assets/javascripts/seapig/seapig-router.js.coffee
|
84
|
+
- app/models/seapig_dependency.rb
|
83
85
|
- app/models/seapig_router_session.rb
|
84
86
|
- app/models/seapig_router_session_state.rb
|
85
87
|
- bin/seapig-notifier
|
@@ -87,8 +89,8 @@ files:
|
|
87
89
|
- config/routes.rb
|
88
90
|
- db/migrate/20151221110834_create_seapig_router_sessions.rb
|
89
91
|
- db/migrate/20151221111628_create_seapig_router_session_states.rb
|
92
|
+
- db/migrate/20151228202111_create_seapig_versions.rb
|
90
93
|
- lib/seapig-rails.rb
|
91
|
-
- lib/seapig/acts_as_seapig_dependency.rb
|
92
94
|
- lib/seapig/engine.rb
|
93
95
|
- lib/seapig/version.rb
|
94
96
|
- lib/seapigs/seapig_router_saved_session.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module SeapigDependency
|
2
|
-
|
3
|
-
module ActsAsSeapigDependency
|
4
|
-
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
|
10
|
-
def acts_as_seapig_dependency(options = {})
|
11
|
-
|
12
|
-
self.instance_eval do
|
13
|
-
|
14
|
-
def seapig_dependency_version
|
15
|
-
self.find_by_sql('SELECT GREATEST(MAX(created_at), MAX(updated_at)) AS version FROM '+table_name).first.version.to_f
|
16
|
-
end
|
17
|
-
|
18
|
-
def seapig_dependency_changed(*tables)
|
19
|
-
tables << self.name
|
20
|
-
connection.instance_variable_get(:@connection).exec("NOTIFY seapig_dependency_changed,'"+tables.map { |table| table.kind_of?(Class) and table.name or table }.uniq.join(',')+"'")
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
ActiveRecord::Base.send :include, SeapigDependency::ActsAsSeapigDependency
|