seapig-rails 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|