Skip to content
Browse files

Remote calls can asynchronously return a result now

New python module common.sql lets you create tables inside the prefs database and execute queries against it
Fix an unhandled exception in broadcasthelper
showMessageBox asynchronously returns the button clicked and allows you to specify which buttons to show
  • Loading branch information...
1 parent 58d850d commit 21451486ecacdf8a2a553ec203dd7f405473014f @kg committed Dec 31, 2010
Showing with 170 additions and 31 deletions.
  1. +14 −7 BroadcastHelper/broadcasthelper.py
  2. +83 −21 Common/Common.cs
  3. +3 −0 Common/Common.csproj
  4. +62 −3 Common/common.py
  5. +8 −0 Common/common.sql.py
View
21 BroadcastHelper/broadcasthelper.py
@@ -57,15 +57,22 @@ def OnFleetBroadcast(self, broadcastType, arg1, charID, locationID, targetID):
if slimItem:
targetName = uix.GetSlimItemName(slimItem)
else:
- location = cfg.evelocations.Get(targetID)
- if location:
- targetName = location.name
+ try:
+ location = cfg.evelocations.Get(targetID)
+ if location:
+ targetName = location.name
+ except:
+ pass
- location = cfg.evelocations.Get(locationID)
- if location:
- locationName = location.name
+ try:
+ location = cfg.evelocations.Get(locationID)
+ if location:
+ locationName = location.name
+ except:
+ pass
- log("Broadcast of type %s by %s with target %s in %s", broadcastType, getCharacterName(charID), targetName, locationName)
+ #log("Broadcast of type %s by %s with target %s in %s", broadcastType, getCharacterName(charID), targetName, locationName)
+
if broadcastType == "Target":
flashItemColor(targetID, "Broadcast: Target")
View
104 Common/Common.cs
@@ -47,6 +47,7 @@ public Common (ScriptName name)
AddDependency("common.eve.logger.py");
AddDependency("common.eve.state.py");
AddDependency("common.eve.charmonitor.py");
+ AddDependency("common.sql.py");
AddDependency("pythonexplorer.py");
CustomMenu = new ToolStripMenuItem("Common");
@@ -126,10 +127,10 @@ public Common (ScriptName name)
MessageQueues[process.Process.Id] = new BlockingQueue<MessageData>();
- process.Start(LogTask(process));
- process.Start(RemoteCallTask(process));
- process.Start(MessageListenerTask(process));
- process.Start(MessageDispatcherTask(process));
+ Start(process, LogTask(process));
+ Start(process, RemoteCallTask(process));
+ Start(process, MessageListenerTask(process));
+ Start(process, MessageDispatcherTask(process));
yield return Program.CallFunction(process, "common", "initialize", process.Process.Id);
}
@@ -140,6 +141,8 @@ public Common (ScriptName name)
if (MessageQueues.ContainsKey(pid))
MessageQueues.Remove(pid);
+ DisposeFuturesForProcess(process);
+
yield break;
}
@@ -243,6 +246,10 @@ public Common (ScriptName name)
string scriptName = callTuple[0] as string;
string methodName = callTuple[1] as string;
object[] rawArguments = callTuple[2] as object[];
+ long? resultId = null;
+
+ if (callTuple.Length >= 4)
+ resultId = Convert.ToInt64(callTuple[3]);
object[] functionArguments;
if (rawArguments == null) {
@@ -267,30 +274,44 @@ public Common (ScriptName name)
continue;
}
- process.Start(RemoteCallInvoker(
+ var fResult = Start(process, RemoteCallInvoker(
instance, methodName, functionArguments, rawArguments, serializer, scriptName, process
));
+
+ if (resultId.HasValue) {
+ fResult.RegisterOnComplete((_) => {
+ object result;
+ Exception error;
+ _.GetResult(out result, out error);
+ Start(process, SendRemoteCallResult(process, resultId.Value, result, error));
+ });
+ }
}
}
+ protected IEnumerator<object> SendRemoteCallResult (ProcessInfo process, long resultId, object result, Exception error) {
+ string errorText = null;
+ if (error != null)
+ errorText = error.ToString();
+ yield return Program.CallFunction(process, "common", "_remoteCallComplete", resultId, result, errorText);
+ }
+
protected IEnumerator<object> RemoteCallInvoker (IManagedScript instance, string methodName, object[] functionArguments, object[] rawArguments, JavaScriptSerializer serializer, string scriptName, ProcessInfo process) {
IEnumerator<object> resultTask = null;
+ object result = null;
- try {
- resultTask = instance.GetType().InvokeMember(
- methodName, BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, instance, functionArguments
- ) as IEnumerator<object>;
- } catch (Exception ex) {
- LogPrint(process,
- "Remote call '{0}.{1}' with args {2} failed with exception: {3}",
- scriptName, methodName, serializer.Serialize(rawArguments), ex.ToString()
- );
+ result = instance.GetType().InvokeMember(
+ methodName, BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, instance, functionArguments
+ );
+ resultTask = result as IEnumerator<object>;
+
+ if (resultTask != null) {
+ var f = Start(process, resultTask);
+ yield return f;
+ yield return new Result(f.Result);
+ } else {
+ yield return new Result(result);
}
-
- if (resultTask != null)
- yield return resultTask;
- else
- yield break;
}
public void LoggedInCharacterChanged (ProcessInfo process, object characterName) {
@@ -305,8 +326,12 @@ public Common (ScriptName name)
yield break;
}
- public void ShowMessageBox (ProcessInfo process, string title, string text) {
- MessageBox.Show(text, title);
+ public string ShowMessageBox (ProcessInfo process, string title, string text) {
+ return MessageBox.Show(text, title).ToString();
+ }
+
+ public string ShowMessageBox (ProcessInfo process, string title, string text, string buttons) {
+ return MessageBox.Show(text, title, (MessageBoxButtons)Enum.Parse(typeof(MessageBoxButtons), buttons)).ToString();
}
public void ShowBalloonTip (ProcessInfo process, string title, string text) {
@@ -359,5 +384,42 @@ public Common (ScriptName name)
Console.WriteLine("Done playing {0}.", soundPath);
}
+
+ public IEnumerator<object> CreateDBTable (ProcessInfo process, string tableName, string tableDef) {
+ yield return Program.CreateDBTable(tableName, tableDef);
+ }
+
+ public IEnumerator<object> ExecuteSQL (ProcessInfo process, string sql, params object[] arguments) {
+ var rows = new List<Dictionary<string, object>>();
+
+ using (var q = Program.Database.BuildQuery(sql)) {
+ var fReader = q.ExecuteReader();
+ yield return fReader;
+
+ using (fReader.Result) {
+ var reader = fReader.Result.Reader;
+ int numColumns = reader.FieldCount;
+ var columnNames = new string[numColumns];
+ for (int i = 0; i < numColumns; i++)
+ columnNames[i] = reader.GetName(i);
+
+ while (true) {
+ var fNext = Future.RunInThread<bool>(reader.Read);
+ yield return fNext;
+
+ if (fNext.Result == false)
+ break;
+
+ var row = new Dictionary<string, object>();
+ for (int i = 0; i < numColumns; i++)
+ row[columnNames[i]] = reader.GetValue(i);
+
+ rows.Add(row);
+ }
+ }
+ }
+
+ yield return new Result(rows.ToArray());
+ }
}
}
View
3 Common/Common.csproj
@@ -119,6 +119,9 @@
<Content Include="common.messaging.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
+ <Content Include="common.sql.py">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
</ItemGroup>
<ItemGroup>
<None Include="evedata.db">
View
65 Common/common.py
@@ -7,6 +7,8 @@
_channels = {}
_pendingMessages = {}
+_pendingRemoteCalls = {}
+_nextRemoteCallId = 1L
isInitialized = False
pid = None
@@ -78,9 +80,66 @@ def showException(etype=None, value=None, tb=None):
))
)
+class RemoteCallResult(object):
+ def __init__(self, stack):
+ self.__stack = stack
+ self.__result = []
+ self.__callbacks = []
+
+ def set(self, result, errorText):
+ if len(self.__result) == 0:
+ self.__result.append((result, errorText))
+
+ while len(self.__callbacks):
+ callback = self.__callbacks.pop()
+ callback(self, result, errorText)
+ else:
+ raise Exception("Already have a result")
+
+ def addCallback(self, callback):
+ if len(self.__result) == 0:
+ self.__callbacks.append(callback)
+ else:
+ r = self.__result[0]
+ callback(r[0], r[1])
+
+ @property
+ def hasResult(self):
+ return len(self.__result) == 1
+
+ @property
+ def result(self):
+ if len(self.__result) == 0:
+ raise Exception("No result yet")
+
+ r = self.__result[0]
+ if r[1] is not None:
+ raise Exception(r[1])
+ else:
+ return r[0]
+
+def _remoteCallComplete(resultId, result, errorText):
+ global _pendingRemoteCalls
+
+ prc = _pendingRemoteCalls.get(resultId, None)
+ if prc is not None:
+ del _pendingRemoteCalls[resultId]
+ prc.set(result, errorText)
+
def remoteCall(script, methodName, *args):
+ global _nextRemoteCallId, _pendingRemoteCalls
+
+ id = _nextRemoteCallId
+ _nextRemoteCallId += 1
+
+ stack = traceback.format_stack()
+ rcr = RemoteCallResult(stack)
+ _pendingRemoteCalls[id] = rcr
+
channel = getChannel("remotecall")
- channel.send(json.dumps([script, methodName, args]))
+ channel.send(json.dumps([script, methodName, args, id]))
+
+ return rcr
def playSound(filename):
moduleName = getCallingModule()
@@ -97,8 +156,8 @@ def showBalloonTip(title, text, timeout=None):
remoteCall("Common.Script.dll", "ShowBalloonTip", *args)
-def showMessageBox(title, text):
- remoteCall("Common.Script.dll", "ShowMessageBox", title, text)
+def showMessageBox(title, text, buttons="OK"):
+ return remoteCall("Common.Script.dll", "ShowMessageBox", title, text, buttons)
def onMainThread():
try:
View
8 Common/common.sql.py
@@ -0,0 +1,8 @@
+from shootblues.common import log, remoteCall
+
+def createTable(name, tableDef):
+ return remoteCall("Common.Script.dll", "CreateDBTable", name, tableDef)
+
+def query(sql, *args):
+ return remoteCall("Common.Script.dll", "ExecuteSQL", sql, *args)
+

0 comments on commit 2145148

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