/// <summary> /// Start a web socket server on a different thread, modifying /// the given interpreter to use it. /// </summary> /// <param name="current">Current interpreter</param> public static Thread WSServeThread(Interpreter current) { var ws = new Grace.Execution.WebSocketServer(); var wss = ws.Start(); var runningThread = Thread.CurrentThread; var runningSink = new WSOutputSink(wss); current.RPCSink = runningSink; wss.JsonReceived += (o, e) => { var je = (JsonWSEvent)e; var root = je.Root; var md = root.XPathSelectElement("//mode"); var mode = md.Value; if (mode == "stop") { Console.WriteLine("Program stopped on remote end."); runningSink.Stop(); runningSink.HardStop(); wss.Stop(); WebSocketEndpoint.Stop(); return; } else if (mode == "response") { processResponse(root); return; } else if (mode == "callback") { if (runningThread != null) { processCallback(root, runningSink); } return; } else if (mode == "ack") { return; } else { Console.WriteLine("unknown mode " + mode); } }; var thread = new Thread(() => { wss.Run(); }); thread.Start(); return(thread); }
/// <summary> /// Send a procedure call over the wire. /// </summary> /// <param name="receiver"> /// Identifier of remote receiving object. /// </param> /// <param name="name"> /// Name of procedure /// </param> /// <param name="args"> /// Array of arguments to the call. /// </param> /// <param name="wait"> /// True to wait for a result, false to return /// done immediately. /// </param> public GraceObject SendCall(int receiver, string name, object[] args, bool wait) { if (hardStop) { Environment.Exit(0); } if (stop) { return(GraceObject.Done); } int theKey = callKey++; var stream = new MemoryStream(10240); var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter( stream ); var xmlDoc = new XmlDocument(); var root = xmlDoc.CreateElement("root"); root.SetAttribute("type", "object"); xmlDoc.AppendChild(root); var mode = xmlDoc.CreateElement("mode"); var tn = xmlDoc.CreateTextNode("call"); mode.AppendChild(tn); root.AppendChild(mode); var reply = xmlDoc.CreateElement("noreply"); reply.SetAttribute("type", "boolean"); tn = xmlDoc.CreateTextNode(wait ? "false" : "true"); reply.AppendChild(tn); root.AppendChild(reply); var rec = xmlDoc.CreateElement("receiver"); rec.SetAttribute("type", "number"); tn = xmlDoc.CreateTextNode("" + receiver); rec.AppendChild(tn); root.AppendChild(rec); var key = xmlDoc.CreateElement("key"); key.SetAttribute("type", "number"); tn = xmlDoc.CreateTextNode("" + theKey); key.AppendChild(tn); root.AppendChild(key); var nameEl = xmlDoc.CreateElement("name"); tn = xmlDoc.CreateTextNode("" + name); nameEl.AppendChild(tn); root.AppendChild(nameEl); var arguments = xmlDoc.CreateElement("args"); arguments.SetAttribute("type", "array"); foreach (var a in args) { var item = xmlDoc.CreateElement("item"); arguments.AppendChild(item); if (a is string) { tn = xmlDoc.CreateTextNode((string)a); item.AppendChild(tn); } else if (a is GraceNumber) { tn = xmlDoc.CreateTextNode(((GraceNumber)a).Double .ToString()); item.AppendChild(tn); item.SetAttribute("type", "number"); } else if (a is GraceBlock) { var b = (GraceBlock)a; int id = getBlockId(b); item.SetAttribute("type", "object"); var obj = xmlDoc.CreateElement("callback"); tn = xmlDoc.CreateTextNode("" + id); obj.AppendChild(tn); item.AppendChild(obj); } else if (a is int[]) { var id = ((int[])a)[0]; item.SetAttribute("type", "object"); var obj = xmlDoc.CreateElement("key"); tn = xmlDoc.CreateTextNode("" + id); obj.AppendChild(tn); item.AppendChild(obj); } } root.AppendChild(arguments); #if DEBUG_WS Console.WriteLine(xmlDoc.OuterXml); #endif xmlDoc.WriteTo(jsonWriter); jsonWriter.Flush(); #if DEBUG_WS Console.WriteLine( "Capacity = {0}, Length = {1}, Position = {2}\n", stream.Capacity.ToString(), stream.Length.ToString(), stream.Position.ToString()); #endif stream.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(stream); EventWaitHandle handle; if (wait) { handle = new EventWaitHandle(false, EventResetMode.ManualReset); WebSocketEndpoint.AddEventHandle(theKey, handle); wss.Send(reader.ReadToEnd()); handle.WaitOne(); return(WebSocketEndpoint.GetEventResult(theKey)); } wss.Send(reader.ReadToEnd()); return(GraceObject.Done); }