/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: MapPointProxy.sg // // Note: A simple proxy module for the MapPoint web service // using System; using System.Diagnostics; using System.Text; using System.Collections; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.MapPointProxy.Contracts; using Microsoft.Singularity.Directory; using Microsoft.Singularity.Xml; using System; using Microsoft.Contracts; using Microsoft.SingSharp.Reflection; using Microsoft.Singularity.Applications; using Microsoft.Singularity.Io; using Microsoft.Singularity.Configuration; using Microsoft.Singularity.Security; [assembly: Transform(typeof(ApplicationResourceTransform))] [assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] [assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] namespace Microsoft.Singularity.Applications { [ConsoleCategory(HelpMessage="Mappoint proxy service", DefaultAction=true)] internal class Parameters { [InputEndpoint("data")] public readonly TRef Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [Endpoint] public readonly TRef nsRef; [StringParameter( "proxy", Mandatory=true, Position=0, HelpMessage="Proxy IP address")] internal string ipAddress; reflective internal Parameters(); internal int AppMain() { return MapPointProxy.AppMain(this); } } public class MapPointProxy { internal static int AppMain(Parameters! config) { string proxyHost = config.ipAddress; //null; //"172.31.40.21"; // msr-proxy // Configure proxy connection. if (proxyHost != null) { Console.WriteLine("MapPoint: HTTP Proxy: {0} port {1}", proxyHost, 80); Console.WriteLine("MapPoint: Alternate proxy can be set on command line."); HttpRequest.ConfigureProxy(proxyHost, 80); } else { Console.WriteLine("MapPoint: No HTTP Proxy configured."); Console.WriteLine("MapPoint: Proxy can be set on command line."); } // Here is the channel we use to communicate with // the NameServer ServiceProviderContract.Imp! nsImp; ServiceProviderContract.Exp! nsExp; ServiceProviderContract.NewChannel(out nsImp, out nsExp); DirectoryServiceContract.Imp ds = config.nsRef.Acquire(); if (ds == null) { throw new Exception("Unable to acquire handle to the Directory Service root"); } ds.RecvSuccess(); try { ds.SendRegister(Bitter.FromString2(MapPointProxyContract.ModuleName), nsImp); switch receive { case ds.AckRegister() : // All is well. break; case ds.NakRegister(ServiceProviderContract.Imp:Start rejectedEP, error) : // All is very much not well; abort. Console.WriteLine("Failed to register the MapPoint proxy module as " + MapPointProxyContract.ModuleName); delete nsExp; delete rejectedEP; return -1; case ds.ChannelClosed(): Console.WriteLine("epNS channel closed"); delete nsExp; return -1; } } finally { delete ds; } // Here is the set of client channels we service ESet epSet = new ESet(); while(true) { switch receive { // ------------------------------- Requests for new connections case nsExp.Connect(ServiceContract.Exp:Start! newEp) : { // We expect people top give us MapPointProxyContract.Exp instances MapPointProxyContract.Exp newMapClient = newEp as MapPointProxyContract.Exp; if (newMapClient == null) { // Invalid contract type. Fail. nsExp.SendNackConnect(newEp); } else { // Signal ready and start servicing this contract nsExp.SendAckConnect(); newMapClient.SendMapPointReady(); epSet.Add(newMapClient); } } break; // ------------------------------- Requests on existing connections // // Don't forget that we're selecting endpoints // from the epSet endpoint-set. In each case that we // receive a message from one of those endpoints, we // need to remember to put the endpoint back into epSet // if we want to keep listening to it. // case ep.GetMap(char[]! in ExHeap centerLat, char[]! in ExHeap centerLong, int zoom, MapPointProxyContract.PushPin[] in ExHeap pushPins) in epSet : { string! xml = BuildXml(centerLat, centerLong, zoom, pushPins); delete centerLat; delete centerLong; delete pushPins; string base64Data = GetBase64MapData(xml); if (base64Data != null) { ep.SendMapDataBegin(); Base64Decoder decoder = new Base64Decoder(base64Data, 0); byte[] chunk; while((chunk = decoder.Pump(base64Data.Length, 4096)) != null) { ep.SendMapDataChunk(Bitter.FromByteArray(chunk)); ep.RecvAck(); } ep.SendDone(); } else { ep.SendFailed(); } epSet.Add(ep); } break; case nsExp.ChannelClosed() && epSet.Empty() : // The namespace channel is closed and we have no more client // channels, so pack up and go home. delete nsExp; epSet.Dispose(); return -1; case ep.ChannelClosed() in epSet : // Dispose of channels when our clients close them delete ep; break; } } return 0; } private static string GetIcon(ref MapPointProxyContract.PushPin pushPin) { expose(pushPin) { return Bitter.ToString(pushPin.icon); } } private static string GetLabel(ref MapPointProxyContract.PushPin pushPin) { expose(pushPin) { return Bitter.ToString(pushPin.label); } } private static string GetLatitude(ref MapPointProxyContract.PushPin pushPin) { expose(pushPin) { return Bitter.ToString(pushPin.latitude); } } private static string GetLongitude(ref MapPointProxyContract.PushPin pushPin) { expose(pushPin) { return Bitter.ToString(pushPin.longitude); } } private static string! BuildXml(char[]! in ExHeap centerLat, char[]! in ExHeap centerLong, int zoom, MapPointProxyContract.PushPin[] in ExHeap pushPins) { string retval = "MapPoint.NADefaultColorDefaultColorDefaultColor50040000"; retval += zoom.ToString(); retval += ""; if (pushPins != null) { for (int i = 0; i < pushPins.Length; ++i) { expose(pushPins[i]) { MapPointProxyContract.PushPin pushPin = pushPins[i]; retval += "MapPoint.Icons"; pushPin.UnExpose(); string icon = GetIcon(ref pushPin); string label = GetLabel(ref pushPin); string latitude = GetLatitude(ref pushPin); string longitude = GetLongitude(ref pushPin); pushPin.Expose(); pushPins[i] = pushPin; if (icon != null) { retval += icon; } retval += ""; retval += latitude; retval += ""; retval += longitude; retval += "falsefalse"; } } } retval += ""; retval += Bitter.ToString2(centerLat); retval += ""; retval += Bitter.ToString2(centerLong); retval += ""; return retval; } private static string GetBase64MapData(string! xml) { HttpRequest request = new HttpRequest("http://renderv3.bay.staging.mappoint.net/Render-30/RenderService.asmx"); request.AddHeader("SOAPAction", "\"http://s.mappoint.net/mappoint-30/GetMap\""); request.ContentType = "text/xml; charset=utf-8"; request.RequestData = Encoding.ASCII.GetBytes(xml); request.Method = "POST"; XmlNode bitsNode = null; try { HttpAuthenticator authenticator = new HttpAuthenticator(request, "7356", "0[[{NmN?UU5?U"); HttpResponse! response = (!)authenticator.GetResponse(); XmlReader xmlReader = new XmlReader(); ArrayList! nodes = (!)xmlReader.Parse(response.BodyData); bitsNode = ((XmlNode!)nodes[0]).GetNestedChild(new string[]{"soap:Body", "GetMapResponse", "GetMapResult", "MapImage", "MimeData", "Bits"}); } catch(Exception) { // Ignore and return null } if (bitsNode != null) { return bitsNode.Text; } else { return null; } } } }