Fixes performance killing potential bug with VueUi (#5199)

So apparently when conditions are right it could make infinite loop (client push -> server receive -> server push -> client receive -> client push...) killing client and server performance.

  <vui-button> now pushes data as JSON, this preserves data structure of parameters
  Store now won't allow state to be pushed if it was very recently received
  There was a plausibly for vueui/Topic() to push data twice, hindering performance. This was mitigated by taking in to consideration object Topic return value if data should pushed.
  Separated some code in to separate file for future reusal or programical uses.
This commit is contained in:
Karolis
2018-09-02 17:01:14 +03:00
committed by Erki
parent c90519f570
commit 8e5c762928
4 changed files with 41 additions and 24 deletions
+22 -12
View File
@@ -229,7 +229,7 @@ main ui datum.
* @return nothing
*/
/datum/vueui/Topic(href, href_list)
update_status()
. = update_status(FALSE)
if(status < STATUS_INTERACTIVE || user != usr)
return
if(href_list["vueuiforceresource"])
@@ -242,13 +242,21 @@ main ui datum.
var/ndata = rdata["state"]
var/ret = object.vueui_data_change(ndata, user, src)
if(ret)
. = TRUE
ndata = ret
push_change(ret)
src.data = ndata
if(href_list["vueuipushonly"])
return
href_list["vueui"] = src // Let's pass our UI object to object for it to do things.
object.Topic(href, href_list)
var/topicReturn = 0
if(!href_list["vueuipushonly"])
if(href_list["vueuihrefjson"])
var/json_href = json_decode(href_list["vueuihrefjson"])
if(json_href)
for(var/hvar in json_href)
href_list[hvar] = json_href[hvar]
href_list["vueui"] = src // Let's pass our UI object to object for it to do things.
topicReturn = object.Topic(href, href_list)
if(. || topicReturn)
. = null
push_change()
/**
* Pushes latest data to client (Including metadata such as: assets index, status, activeui)
@@ -286,13 +294,15 @@ main ui datum.
*
* @return nothing
*/
/datum/vueui/proc/set_status(nstatus)
/datum/vueui/proc/set_status(var/nstatus, var/autopush = TRUE)
if (nstatus != status) // Only update if it is different
status = nstatus
if(nstatus > STATUS_DISABLED)
check_for_change(1) // Gather data and update it
else if (nstatus == STATUS_DISABLED)
push_change(null) // Only update ui data
if(autopush) check_for_change(1) // Gather data and update it
return 1
else if (nstatus == STATUS_DISABLED && autopush)
if(autopush) push_change(null) // Only update ui data
return 1
else
close()
@@ -301,8 +311,8 @@ main ui datum.
*
* @return nothing
*/
/datum/vueui/proc/update_status()
set_status(object.CanUseTopic(user, state))
/datum/vueui/proc/update_status(var/autopush = TRUE)
. = set_status(object.CanUseTopic(user, state), autopush)
/**
* Process this ui
+2 -12
View File
@@ -7,7 +7,7 @@
<script>
import Store from '../../store.js'
import Utils from '../../utils.js'
export default {
props: {
icon: {
@@ -41,17 +41,7 @@ export default {
}
return
}
var sendparams = []
for(var val in this.params) {
sendparams.push(encodeURIComponent(val) + "=" + encodeURIComponent(this.params[val]))
}
var r = new XMLHttpRequest()
var sendUrl = "?src=" + Store.state.uiref + "&" + sendparams.join("&")
if (this.pushState) {
sendUrl += "&" + Store.getStatePushString()
}
r.open("GET", sendUrl, true);
r.send()
Utils.sendToTopic(this.params, this.pushState)
}
}
}
+5
View File
@@ -10,6 +10,7 @@ export default {
},
loadState (loadedState) {
this.isUpdating = true
this.lastUpdateTime = Date.now()
if (this.debug) console.log('Loaded state with', loadedState)
this.state.assets = loadedState.assets
Object.keys(loadedState.state).forEach((key) => {
@@ -23,10 +24,14 @@ export default {
this.isUpdating = false
},
isUpdating: false,
lastUpdateTime: null,
getStatePushString () {
return "vueuistateupdate=" + encodeURIComponent(JSON.stringify(this.state))
},
pushState() {
if (this.isUpdating || (Date.now() - this.lastUpdateTime) < 100 ) {
return
}
var r = new XMLHttpRequest()
r.open("GET", "?src=" + this.state.uiref + "&vueuipushonly=1&" + this.getStatePushString(), true);
r.send()
+12
View File
@@ -0,0 +1,12 @@
import Store from './store.js'
export default {
sendToTopic(data, pushState = false) {
var r = new XMLHttpRequest()
var sendUrl = "?src=" + Store.state.uiref + "&vueuihrefjson=" + encodeURIComponent(JSON.stringify(data))
if (pushState) {
sendUrl += "&" + Store.getStatePushString()
}
r.open("GET", sendUrl, true);
r.send()
}
}