public SSClient( Uri gingaHttpLocation, OnActionReceivedMethod onActionReceived = null, Action onServerDisconnected = null){ DebugStream.outPut += "SSClient.SSClient: entrei.\n"; this.gingaUrl = new Uri(string.Format("http://{0}:{1}/",gingaHttpLocation.Host,gingaHttpLocation.Port)); this.httpViceVersa = new HttpBridge(this.OnHttpServerRequested); this.OnServerDisconnected = onServerDisconnected; this.OnActionReceived = onActionReceived; DebugStream.outPut += "SSClient.SSClient: pre-inicialização.\n"; // Register request body JObject body = new JObject( new JProperty("location",string.Format("http://{0}:{1}/",Array.Find(Dns.GetHostEntry(Dns.GetHostName()).AddressList,i => i.AddressFamily == AddressFamily.InterNetwork),this.httpViceVersa.Port)), new JProperty("deviceType","VR"), new JProperty("supportedFormats",new JArray( new JValue("x-application-ncl360"), new JValue("x-application-x3d"), new JValue("x-application-aframe") )), new JProperty("recognizableEvents",new JArray( new JValue("selection"), new JValue("lookAt"), new JValue("lookAway") )) ); DebugStream.outPut += "SSClient.SSClient: registrando\n"; // Step two: register its server as a client var postResp = this.Post("dtv/remote-mediaplayer/",body,new Tuple<string,string>[]{ Tuple.Create("Content-Type","application/json; charset=utf-8"), Tuple.Create("Accept","application/json; charset=utf-8") }); // ################################ DebugStream.outPut += "A response da POST request a: " + postResp.RequestUri.ToString() + " HEADERS:\n\n"; foreach( var key in postResp.ResponseHeaders.AllKeys) DebugStream.outPut += "Key: \"" + key + "\" Value: \"" + postResp.ResponseHeaders[key] + "\"\n"; DebugStream.outPut += "\nBODY:\n\"" + postResp.ResponseBody + "\"\n"; // ################################ if( postResp.BadParsed ) throw new Exception("The register response was bad parsed!"); if( !postResp.ResponseBody.ContainsKey("control") || postResp.ResponseBody.GetValue("control") == null ) throw new Exception("The register response has no well formed 'control' key!"); DebugStream.outPut += "SSClient.SSClient: passo 2\n"; // Step three: creates and configures the TCP socket connection this.connection = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp){ Blocking = true }; if( Array.Find(Dns.GetHostEntry(gingaHttpLocation.Host).AddressList,i => i.AddressFamily == AddressFamily.InterNetwork) == null ) throw new Exception("Ginga HTTP server hostnome could not be resolved to an IPv4!"); // Starts a timer coroutine once csharp doesn't have a TimeOut parameter var timer = new Thread(() => { Thread.Sleep(60000); if( !this.connection.Connected ) this.connection.Close(); }); timer.IsBackground = true; timer.Start(); try{ DebugStream.outPut += "SSClient.SSClient: finishing handshake\n"; this.connection.Connect( Array.Find(Dns.GetHostEntry(gingaHttpLocation.Host).AddressList,i => i.AddressFamily == AddressFamily.InterNetwork), int.Parse(postResp.ResponseBody.GetValue("control").ToString()) ); DebugStream.outPut += "SSClient.SSClient: handshake finished\n"; ThreadStart connectionControlerDaemon = () => { try{ // The server shall never send a single byte, then it blocks until the connection is broken while( this.connection.Receive(new byte[1],1,SocketFlags.None) != 0 ); }catch( SocketException){ DebugStream.outPut += "\n\nConnection closed!\n"; } // Once disconnected... if( this.OnServerDisconnected != null ) this.OnServerDisconnected(); }; // Once connected, the connection controler is launched var control = new Thread(connectionControlerDaemon); control.IsBackground = true; control.Start(); }catch( SocketException){ DebugStream.outPut += "\n\nControl connection timed out!\n"; } }
// ################################ // ############# HTTP ############# // ################################ #region HTTP public IEnumerator OnHttpServerRequested( HttpListenerContext context){ // ################################ // Get and parse the input HttpBridge.ParsedReceivedRequest parsedRequest = null; // Get a parsed input (syncronous) var task = Task.Factory.StartNew(() => parsedRequest = new HttpBridge.ParsedReceivedRequest(context.Request)); yield return new WaitUntil(() => task.IsCompleted); task.Dispose(); // ################################################################ DebugStream.outPut += "\nA request de método: " + context.Request.HttpMethod + " e URL: " + context.Request.Url.OriginalString + " vinda de: " + context.Request.RemoteEndPoint.Address.ToString() + ": HEADERS:\n\n"; foreach( var key in parsedRequest.Headers.AllKeys) DebugStream.outPut += "key: \"" + key + "\" Value: \"" + parsedRequest.Headers[key] + "\"\n"; DebugStream.outPut += "\nBODY:\n\"" + parsedRequest.Body + "\"\n"; // ################################################################ // ################################ // Process the input JObject responseMsg = null; // It's a bad request if( parsedRequest.BadParsed ){ responseMsg = new JObject(new JProperty("error","Request body is not UTF-8 encoded JSON (bad parse).")); context.Response.StatusCode = (int) HttpStatusCode.BadRequest; // It's an action message }else if( context.Request.HttpMethod == HttpMethod.Post.ToString() && context.Request.Url.AbsolutePath.StartsWith(ACTION_PREFIX) && context.Request.ContentType == "application/json; charset=utf-8" && context.Request.AcceptTypes.Contains("application/json; charset=utf-8") ){ // Clean up var relPath = context.Request.Url.AbsolutePath.Substring(ACTION_PREFIX.Length); var body = parsedRequest.Body; parsedRequest = null; // Possible exception Exception e = null; // Call the request correct treatment if( this.OnActionReceived != null ) yield return this.OnActionReceived(relPath,body,value => responseMsg = value,value => e = value); if( e == null ){ if( responseMsg == null ) responseMsg = new JObject(); context.Response.StatusCode = (int) HttpStatusCode.OK; }else{ responseMsg = new JObject(new JProperty("error","Action not accepted:\n\n" + e.ToString())); context.Response.StatusCode = (int) HttpStatusCode.BadRequest; } }else{ responseMsg = new JObject(new JProperty("error","unrecognizable request.")); context.Response.StatusCode = (int) HttpStatusCode.BadRequest; // ##################################################### DebugStream.outPut += "Recebi requisição inválida...\n"; } // ##################################################### DebugStream.outPut += "enviando response\n"; // ################################ // Send the output var respondAsync = Task.Factory.StartNew(() => { try{ HttpBridge.SendRequestResponse(context.Response,responseMsg,Encoding.UTF8,new Tuple<string,string>[]{ Tuple.Create("Content-Type","application/json; charset=utf-8") }); }catch( Exception e){ DebugStream.outPut += "Capturada exceção no envio da resposta:\n\n" + e.ToString() + "\n"; } }); yield return new WaitUntil(() => respondAsync.IsCompleted); respondAsync.Dispose(); // ##################################################### DebugStream.outPut += "response enviada\n"; }