Skip to content
Browse files

Implement workaround for webkit memory leak

  • Loading branch information...
1 parent 69ff5ed commit 6a2b1bcbb83d7b217bbe6ba554a7d97ddb798cc6 @kg committed Dec 16, 2010
View
81 Python/NotificationListener.Script.Py
@@ -0,0 +1,81 @@
+from shootblues import Dependency
+Dependency("Common.Script.dll")
+Dependency("EventNotifications.Script.dll")
+
+from shootblues.common import log
+from shootblues.common.eve import runOnMainThread
+from shootblues.common.service import forceStart, forceStop
+import util
+from HTMLParser import HTMLParser
+
+from shootblues.eventnotifications import DefineEvent, fireEvent
+DefineEvent("UnreadNotification")
+
+serviceInstance = None
+
+class MLStripper(HTMLParser):
+ def __init__(self):
+ self.reset()
+ self.fed = []
+ def handle_data(self, d):
+ self.fed.append(d)
+ def get_data(self):
+ return ''.join(self.fed)
+
+def strip_tags(html):
+ s = MLStripper()
+ s.feed(html)
+ return s.get_data()
+
+def getName(o):
+ if o:
+ return o.name
+ else:
+ return "None"
+
+class NotificationListenerSvc:
+ __notifyevents__ = [
+ "OnNotificationReceived",
+ "OnSessionChanged"
+ ]
+
+ def __init__(self):
+ runOnMainThread(self.checkUnreadNotifications)
+
+ def checkUnreadNotifications(self):
+ notifyService = sm.services.get("notificationSvc", None)
+ if not notifyService:
+ return
+
+ if not eve.session.charid:
+ return
+
+ unreadNotifications = notifyService.GetFormattedUnreadNotifications()
+
+ if len(unreadNotifications):
+ for n in unreadNotifications:
+ fireEvent("UnreadNotification", text=strip_tags(str(n.body)))
+
+ notifyIDs = [n.notificationID for n in unreadNotifications]
+ notifyService.MarkAsRead(notifyIDs)
+ notifyService.UpdateCacheAfterMarkingRead(notifyIDs)
+
+ def OnSessionChanged(self, isRemote, session, change):
+ self.checkUnreadNotifications()
+
+ def OnNotificationReceived(self, notificationID, typeID, senderID, created, data={}):
+ notifyService = sm.services.get("notificationSvc", None)
+ if not notifyService:
+ return
+
+ self.checkUnreadNotifications()
+
+def __load__():
+ global serviceInstance
+ serviceInstance = forceStart("notificationlistener", NotificationListenerSvc)
+
+def __unload__():
+ global serviceInstance
+ if serviceInstance:
+ forceStop("notificationlistener")
+ serviceInstance = None
View
102 Python/TowermailForwarder.Script.py
@@ -0,0 +1,102 @@
+from shootblues import Dependency
+Dependency("Common.Script.dll")
+Dependency("EventNotifications.Script.dll")
+
+from shootblues.common import log
+from shootblues.common.eve import runOnMainThread
+from shootblues.common.service import forceStart, forceStop
+import util
+from HTMLParser import HTMLParser
+
+from shootblues.eventnotifications import DefineEvent, fireEvent
+DefineEvent("NewTowermail")
+
+TowermailFormat = (
+ "{subject} // {timestamp}",
+ "Moon: {moonName} // Object: {typeName} // Current Shield Level: {shieldPercentage}%",
+ "Pilot: {aggressorName} // Corp: {aggressorCorpName} // Alliance: {aggressorAllianceName}"
+)
+
+serviceInstance = None
+
+class MLStripper(HTMLParser):
+ def __init__(self):
+ self.reset()
+ self.fed = []
+ def handle_data(self, d):
+ self.fed.append(d)
+ def get_data(self):
+ return ''.join(self.fed)
+
+def strip_tags(html):
+ s = MLStripper()
+ s.feed(html)
+ return s.get_data()
+
+def getName(o):
+ if o:
+ return o.name
+ else:
+ return "None"
+
+class TowermailSvc:
+ __notifyevents__ = [
+ "OnNotificationReceived",
+ "OnSessionChanged"
+ ]
+
+ def __init__(self):
+ runOnMainThread(self.checkUnreadNotifications)
+
+ def formatTowermail(self, n):
+ data = n.data.copy()
+ data["subject"] = strip_tags(str(n.subject))
+ data["body"] = strip_tags(str(n.body))
+ data["timestamp"] = util.FmtDate(n.created)
+ data["moonName"] = getName(cfg.evelocations.Get(n.data["moonID"]))
+ data["typeName"] = getName(cfg.invtypes.Get(n.data["typeID"]))
+ data["aggressorName"] = getName(cfg.eveowners.Get(n.data["aggressorID"]))
+ data["aggressorCorpName"] = getName(cfg.eveowners.Get(n.data["aggressorCorpID"]))
+ data["aggressorAllianceName"] = getName(cfg.eveowners.Get(n.data["aggressorAllianceID"]))
+ data["shieldPercentage"] = int(float(n.data["shieldValue"]) * 100)
+ return [l.format(**data) for l in TowermailFormat]
+
+ def checkUnreadNotifications(self):
+ notifyService = sm.services.get("notificationSvc", None)
+ if not notifyService:
+ return
+
+ if not eve.session.charid:
+ return
+
+ towermails = [n for n in notifyService.GetFormattedUnreadNotifications()
+ if n.typeID == const.notificationTypeTowerAlertMsg]
+
+ if len(towermails):
+ for n in towermails:
+ formatted = self.formatTowermail(n)
+ fireEvent("NewTowermail", text=formatted)
+
+ notifyIDs = [n.notificationID for n in towermails]
+ notifyService.MarkAsRead(notifyIDs)
+ notifyService.UpdateCacheAfterMarkingRead(notifyIDs)
+
+ def OnSessionChanged(self, isRemote, session, change):
+ self.checkUnreadNotifications()
+
+ def OnNotificationReceived(self, notificationID, typeID, senderID, created, data={}):
+ notifyService = sm.services.get("notificationSvc", None)
+ if not notifyService:
+ return
+
+ self.checkUnreadNotifications()
+
+def __load__():
+ global serviceInstance
+ serviceInstance = forceStart("towermail", TowermailSvc)
+
+def __unload__():
+ global serviceInstance
+ if serviceInstance:
+ forceStop("towermail")
+ serviceInstance = None
View
3 RemoteControl/RemoteControl.cs
@@ -518,6 +518,7 @@ public RemoteControl (ScriptName name)
long frameIndex = long.Parse(context.Request.QueryString["i"]);
context.Response.AppendHeader("Cache-Control", "no-store, no-cache, private");
+ context.Response.AppendHeader("Pragma", "no-cache");
context.Response.ContentType = "image/jpeg";
yield return Future.RunInThread(() => {
@@ -758,6 +759,7 @@ public RemoteControl (ScriptName name)
}
context.Response.ContentType = "text/html";
+ context.Response.AddHeader("X-UA-Compatible", "IE=edge");
using (var resp = context.GetResponseWriter(Encoding.UTF8)) {
yield return resp.WriteLines(
@@ -918,6 +920,7 @@ public RemoteControl (ScriptName name)
}
context.Response.ContentType = "text/html";
+ context.Response.AddHeader("X-UA-Compatible", "IE=edge");
var sauce = GetSauceForUser(context, false);
View
2 RemoteControl/RemoteControlConfig.cs
@@ -213,7 +213,7 @@ public RemoteControlConfig (RemoteControl script)
this.MaxFrameRate.Size = new System.Drawing.Size(95, 23);
this.MaxFrameRate.TabIndex = 8;
this.MaxFrameRate.Value = new decimal(new int[] {
- 30,
+ 20,
0,
0,
0});
View
3 RemoteControl/login.html
@@ -1,4 +1,5 @@
-<html>
+<!DOCTYPE HTML>
+<html>
<head>
<title>EVE Remote Control - Login</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
View
90 RemoteControl/process_index.html
@@ -1,4 +1,5 @@
-<html>
+<!DOCTYPE HTML>
+<html>
<head>
<title>EVE Remote Control - {authLevel} - {pid}</title>
@@ -18,6 +19,13 @@
overflow: hidden;
}
+ #fuck_webkit {
+ overflow: hidden;
+ padding: 0px;
+ margin: 0px;
+ display: none;
+ }
+
#modes, #channels {
margin: 0px;
padding: 0px;
@@ -37,9 +45,17 @@
display: none;
}
</style>
- <meta http-equiv="X-UA-Compatible" content="IE=edge" />
</head>
<body>
+ <!--
+ Workaround for WebKit memory leak:
+ All resources loaded from within a document in WebKit are cached for the life of that document.
+ Since the contents of an iframe are their own document, using an iframe to load images instead of
+ an IMG tag prevents us from leaking unbounded amounts of memory by loading our delta images.
+ This is retarded.
+ -->
+ <iframe id="fuck_webkit" src="about:blank"></iframe>
+
<div id="modes">
<ul>
<li>
@@ -77,8 +93,14 @@
var eventQueue = [];
var eventInProgress = false;
var scaleRatio = 1.0;
+ var isActive = false;
function updateViewport (pixels, indices) {
+ if ((indices.length == 0) || !isActive) {
+ updateInProgress = false;
+ return;
+ }
+
var vp = document.getElementById("viewport");
var vpc = vp.getContext("2d");
var bb = document.getElementById("backbuffer");
@@ -103,16 +125,23 @@
bb.width = srcWidth;
bb.height = srcHeight;
}
- bbc.drawImage(pixels, 0, 0, srcWidth, srcHeight);
+ try {
+ bbc.drawImage(pixels, 0, 0, srcWidth, srcHeight);
+ } catch(e) {
+ }
} else if (indices.length > 1) {
// Deltas
var l = indices.length;
for (var i = 1; i < l; i++) {
var idx = indices[i];
- bbc.drawImage(
- pixels, (i - 1) * blockSize, 0, blockSize, blockSize,
- idx["x"], idx["y"], blockSize, blockSize
- );
+ try {
+ bbc.drawImage(
+ pixels, (i - 1) * blockSize, 0, blockSize, blockSize,
+ idx["x"], idx["y"], blockSize, blockSize
+ );
+ } catch(e) {
+ break;
+ }
}
}
@@ -128,22 +157,20 @@
updateInProgress = false;
}
- function refreshImage (force) {
+ function refreshImage (forceKeyframe) {
if (updateInProgress)
return;
- if (!force) {
- var isVisible = $("#viewport").is(":visible");
- if (!isVisible)
- return;
- }
+ if (!forceKeyframe && !isActive)
+ return;
var error = "error";
var data = {
"deltas": null,
"indices": null
};
- var newDeltas = document.createElement("img");
+
+ var iframe = document.getElementById("fuck_webkit");
var sync = function () {
if ((data.deltas == null) || (data.indices == null))
@@ -157,28 +184,31 @@
window.setTimeout(sync, 1);
else {
updateInProgress = true;
- window.setTimeout(refreshImage, 33);
+ window.setTimeout(function() { refreshImage(false) }, 50);
updateViewport(data.deltas, data.indices);
}
} else {
- window.setTimeout(refreshImage, 1000);
+ window.setTimeout(function() { refreshImage(false) }, 5000);
}
data.deltas = null;
data.indices = null;
};
- counter += 1;
+ if (forceKeyframe)
+ counter += 2;
+ else
+ counter += 1;
var onLoad, onError;
var cleanup = function () {
- newDeltas.removeEventListener("load", onLoad, true);
- newDeltas.removeEventListener("error", onError, true);
+ iframe.removeEventListener("load", onLoad, true);
+ iframe.removeEventListener("error", onError, true);
};
onLoad = function () {
- data.deltas = newDeltas;
+ data.deltas = iframe.contentDocument.getElementsByTagName("img")[0];
cleanup();
sync();
};
@@ -189,10 +219,11 @@
sync();
};
- newDeltas.addEventListener("load", onLoad, true);
- newDeltas.addEventListener("error", onError, true);
+ iframe.addEventListener("load", onLoad, true);
+ iframe.addEventListener("error", onError, true);
+
+ iframe.setAttribute("src", "viewport/deltas?i=" + counter);
- newDeltas.setAttribute("src", "viewport/deltas?i=" + counter);
$.getJSON(
"viewport/indices",
{"i": counter},
@@ -240,8 +271,8 @@
function getMouseArgs (evt) {
var vp = document.getElementById("viewport");
var result = {
- "x": Math.floor((evt.pageX - viewport.offsetLeft) / scaleRatio),
- "y": Math.floor((evt.pageY - viewport.offsetTop) / scaleRatio)
+ "x": Math.floor((evt.pageX - vp.offsetLeft) / scaleRatio),
+ "y": Math.floor((evt.pageY - vp.offsetTop) / scaleRatio)
};
if ((evt.which >= 1) && (evt.which <= 3)) {
var buttonNames = ["Left", "Middle", "Right"];
@@ -293,8 +324,11 @@
evt.preventDefault();
}
- function onModeSelect (evt) {
- refreshImage(true);
+ function onModeSelect (evt, ui) {
+ isActive = (ui.index == 0);
+
+ if (isActive)
+ refreshImage(true);
}
function initialize () {
@@ -312,6 +346,8 @@
$(document).bind("keydown", onKeyDown);
$(document).bind("keyup", onKeyUp);
$(document).bind("keypress", onKeyPress);
+
+ isActive = true;
refreshImage(true);
}

0 comments on commit 6a2b1bc

Please sign in to comment.
Something went wrong with that request. Please try again.