protected virtual void OnPostProcessRequest(MigClientRequest request) { if (request != null && PostProcessRequest != null) { PostProcessRequest(this, new ProcessRequestEventArgs(request)); } }
public void ProcessRequest(MessageEventArgs args) { var migContext = new MigContext(ContextSource.WebSocketGateway, args); var migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(args.Data)); OnPreProcessRequest(migRequest); if (!migRequest.Handled) { OnPostProcessRequest(migRequest); } }
public void ProcessRequest(MigClientRequest request) { var context = request.Context.Data as HttpListenerContext; var requestOrigin = context.Request.RemoteEndPoint.Address.ToString(); var migCommand = request.Command; switch (migCommand.Command) { case "Events.Push": //TODO: implemet security and trust mechanism var stream = request.RequestText; var moduleEvent = JsonConvert.DeserializeObject <ModuleEvent>( stream, new JsonSerializerSettings() { Culture = System.Globalization.CultureInfo.InvariantCulture } ); // prefix remote event domain with HGIC:<remote_node_address>.<domain> moduleEvent.Module.Domain = "HGIC:" + requestOrigin.Replace(".", "_") + "." + moduleEvent.Module.Domain; // var module = homegenie.Modules.Find(delegate(Module o) { return(o.Domain == moduleEvent.Module.Domain && o.Address == moduleEvent.Module.Address); }); if (module == null) { module = moduleEvent.Module; homegenie.Modules.Add(module); } Utility.ModuleParameterSet(module, moduleEvent.Parameter.Name, moduleEvent.Parameter.Value); // "<ip>:<port>" remote endpoint port is passed as the first argument from the remote point itself module.RoutingNode = requestOrigin + (migCommand.GetOption(0) != "" ? ":" + migCommand.GetOption(0) : ""); // homegenie.RaiseEvent( requestOrigin, moduleEvent.Module.Domain, moduleEvent.Module.Address, requestOrigin, moduleEvent.Parameter.Name, moduleEvent.Parameter.Value ); var eventData = new ProgramManager.RoutedEvent() { Sender = requestOrigin, Module = module, Parameter = moduleEvent.Parameter }; ThreadPool.QueueUserWorkItem(new WaitCallback(homegenie.ProgramManager.RoutePropertyChangedEvent), eventData); break; } }
public void ProcessRequest(ServerDataEventArgs args) { UTF8Encoding encoding = new UTF8Encoding(); var message = encoding.GetString(args.Data, 0, args.DataLength); var migContext = new MigContext(ContextSource.TcpSocketGateway, args); var migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(message)); OnPreProcessRequest(migRequest); if (!migRequest.Handled) { OnPostProcessRequest(migRequest); } }
public void ProcessRequest(MigClientRequest request) { var migCommand = request.Command; string response = ""; string domain = ""; string address = ""; int domainSeparator = 0; DateTime dateStart, dateEnd; switch (migCommand.Command) { case "Global.CounterTotal": var counter = homegenie.Statistics.GetTotalCounter(migCommand.GetOption(0), 3600); request.ResponseData = new ResponseText(counter.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture)); break; case "Global.TimeRange": var totalRange = homegenie.Statistics.GetDateRange(); request.ResponseData = "{ \"StartTime\" : \"" + Utility.DateToJavascript(totalRange.TimeStart).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "\", \"EndTime\" : \"" + Utility.DateToJavascript(totalRange.TimeEnd).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "\" }"; break; case "Database.Reset": homegenie.Statistics.ResetDatabase(); break; case "Configuration.Get": // Just one at the moment. request.ResponseData = "{ \"StatisticsUiRefreshSeconds\" : \"" + homegenie.SystemConfiguration.HomeGenie.Statistics.StatisticsUiRefreshSeconds + "\" }"; break; case "Parameter.List": domainSeparator = migCommand.GetOption(0).LastIndexOf(":"); if (domainSeparator > 0) { domain = migCommand.GetOption(0).Substring(0, domainSeparator); address = migCommand.GetOption(0).Substring(domainSeparator + 1); } response = "["; foreach (string statParameter in homegenie.Statistics.GetParametersList(domain, address)) { response += " \""+ statParameter + "\",\n"; } response = response.TrimEnd(',', '\n'); response += "\n]"; request.ResponseData = response; break; case "Parameter.Counter": domainSeparator = migCommand.GetOption(1).LastIndexOf(":"); if (domainSeparator > 0) { domain = migCommand.GetOption(1).Substring(0, domainSeparator); address = migCommand.GetOption(1).Substring(domainSeparator + 1); } // response = "["; response += "[ "; // var hoursAverage = new List <StatisticsEntry>(); dateStart = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(2))); dateEnd = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(3))); hoursAverage = homegenie.Statistics.GetHourlyCounter(domain, address, migCommand.GetOption(0), 3600, dateStart, dateEnd); // for (int h = 0; h < 24; h++) { StatisticsEntry firstEntry = null; if (hoursAverage != null && hoursAverage.Count > 0) { firstEntry = hoursAverage.Find(se => se.TimeStart.ToLocalTime().Hour == h); } // if (firstEntry != null) { double sum = 0; sum = (double)(hoursAverage.FindAll(se => se.TimeStart.ToLocalTime().Hour == h).Sum(se => se.Value)); // date is normalized to the current date, time info is preserved from original data entry var date = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd") + " " + h.ToString("00") + ":00:00"); response += "[" + Utility.DateToJavascript(date).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "," + sum.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "],"; } else { var date = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd") + " " + h.ToString("00") + ":00:00"); response += "[" + Utility.DateToJavascript(date).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + ",0.000],"; } } response = response.TrimEnd(','); response += " ]"; response += "]"; request.ResponseData = response; break; case "Parameter.StatsHour": domainSeparator = migCommand.GetOption(1).LastIndexOf(":"); if (domainSeparator > 0) { domain = migCommand.GetOption(1).Substring(0, domainSeparator); address = migCommand.GetOption(1).Substring(domainSeparator + 1); } // response = "["; // dateStart = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(2))); dateEnd = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(3))); var hoursAverages = new List <StatisticsEntry> [5]; hoursAverages[0] = homegenie.Statistics.GetHourlyStats(domain, address, migCommand.GetOption(0), "Min", dateStart, dateEnd); hoursAverages[1] = homegenie.Statistics.GetHourlyStats(domain, address, migCommand.GetOption(0), "Max", dateStart, dateEnd); hoursAverages[2] = homegenie.Statistics.GetHourlyStats(domain, address, migCommand.GetOption(0), "Avg", dateStart, dateEnd); hoursAverages[3] = homegenie.Statistics.GetHourlyStatsToday(domain, address, migCommand.GetOption(0), "Avg"); if (migCommand.GetOption(0).StartsWith(Properties.MeterAny)) { hoursAverages[4] = homegenie.Statistics.GetTodayDetail(domain, address, migCommand.GetOption(0), "Sum"); } else { hoursAverages[4] = homegenie.Statistics.GetTodayDetail(domain, address, migCommand.GetOption(0), "Avg"); } // for (int x = 0; x < 4; x++) { response += "[ "; for (int h = 0; h < 24; h++) { StatisticsEntry firstEntry = null; if (hoursAverages[x] != null && hoursAverages[x].Count > 0) { if (migCommand.GetOption(0).StartsWith(Properties.MeterAny)) { firstEntry = hoursAverages[x].Find(se => se.TimeStart.ToLocalTime().Hour == h && se.Value > 0); } else { firstEntry = hoursAverages[x].Find(se => se.TimeStart.ToLocalTime().Hour == h); } } // if (firstEntry != null) { double sum = 0; switch (x) { case 0: if (migCommand.GetOption(0).StartsWith(Properties.MeterAny)) { sum = (double)(hoursAverages[x].FindAll(se => se.TimeStart.ToLocalTime().Hour == h && se.Value > 0).Min(se => se.Value)); } else { sum = (double)(hoursAverages[x].FindAll(se => se.TimeStart.ToLocalTime().Hour == h).Min(se => se.Value)); } break; case 1: sum = (double)(hoursAverages[x].FindAll(se => se.TimeStart.ToLocalTime().Hour == h).Max(se => se.Value)); break; case 2: if (migCommand.GetOption(0).StartsWith(Properties.MeterAny)) { sum = (double)(hoursAverages[x].FindAll(se => se.TimeStart.ToLocalTime().Hour == h && se.Value > 0).Average(se => se.Value)); } else { sum = (double)(hoursAverages[x].FindAll(se => se.TimeStart.ToLocalTime().Hour == h).Average(se => se.Value)); } break; case 3: if (migCommand.GetOption(0).StartsWith(Properties.MeterAny)) { sum = (double)(hoursAverages[x].FindAll(se => se.TimeStart.ToLocalTime().Hour == h && se.Value > 0).Average(se => se.Value)); } else { sum = (double)(hoursAverages[x].FindAll(se => se.TimeStart.ToLocalTime().Hour == h).Average(se => se.Value)); } break; } // date is normalized to the current date, time info is preserved from original data entry var date = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd") + " " + h.ToString("00") + ":00:00"); response += "[" + Utility.DateToJavascript(date).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "," + sum.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "],"; } else { var date = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd") + " " + h.ToString("00") + ":00:00"); response += "[" + Utility.DateToJavascript(date).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + ",0.000],"; } } response = response.TrimEnd(','); response += " ],"; } // response += "[ "; foreach (var entry in hoursAverages[4]) { var date = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd") + " " + entry.TimeStart.ToLocalTime().ToString("HH:mm:ss.ffffff")); response += "[" + Utility.DateToJavascript(date).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "," + entry.Value.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "],"; } response = response.TrimEnd(','); response += " ]"; // response += "]"; request.ResponseData = response; break; case "Parameter.StatsDay": domainSeparator = migCommand.GetOption(1).LastIndexOf(":"); if (domainSeparator > 0) { domain = migCommand.GetOption(1).Substring(0, domainSeparator); address = migCommand.GetOption(1).Substring(domainSeparator + 1); } // response = "["; // dateStart = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(2))); dateEnd = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(3))); var daysAverages = new List <StatisticsEntry> [1]; daysAverages[0] = homegenie.Statistics.GetHourlyStats(domain, address, migCommand.GetOption(0), "", dateStart, dateEnd); response += "[ "; foreach (var entry in daysAverages[0]) { response += "[" + Utility.DateToJavascriptLocal(entry.TimeStart).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "," + entry.Value.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "],"; } response = response.TrimEnd(','); response += " ]"; // response += "]"; request.ResponseData = response; break; case "Parameter.StatsMultiple": response = "["; // dateStart = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(2))); dateEnd = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(3))); var daysMultiples = new List <StatisticsEntry> [1]; daysMultiples[0] = homegenie.Statistics.GetHourlyStats(domain, address, migCommand.GetOption(0), "All", dateStart, dateEnd); response += "[ "; var moduleName = ""; foreach (var entry in daysMultiples[0]) { if (entry.CustomData == "") { entry.CustomData = entry.Domain + ":" + entry.Address; } if (moduleName != entry.CustomData) { if (moduleName != "") { response = response.TrimEnd(','); response += " ],[ "; } response += "[\"" + entry.CustomData + "\"] ],[ "; moduleName = entry.CustomData; } response += "[" + Utility.DateToJavascriptLocal(entry.TimeStart).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "," + entry.Value.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "],"; } response = response.TrimEnd(','); response += " ]"; /*response += "[ "; * var moduleName = ""; * foreach (var entry in daysMultiples[0]) * { * if (entry.CustomData == "") * entry.CustomData = entry.Domain + ":" + entry.Address; * if(moduleName != entry.CustomData) * { * if(moduleName != "") * { * response = response.TrimEnd(','); * response += " ] ],[ "; * } * response += "[ \""+entry.CustomData + "\" ],[ "; * moduleName = entry.CustomData; * } * response += "[" + DateToJavascriptLocal(entry.TimeStart).ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "," + entry.Value.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture) + "],"; * } * response = response.TrimEnd(','); * response += " ]"; * if(moduleName != "") * response += " ]";*/ // response += "]"; request.ResponseData = response; break; case "Parameter.StatRemove": var dateText = migCommand.GetOption(0).Replace('.', ','); dateStart = Utility.JavascriptToDateUtc(double.Parse(dateText)); homegenie.Statistics.DeleteData(dateStart, migCommand.GetOption(1)); request.ResponseData = new ResponseText("OK"); break; } }
private void Worker(object state) { HttpListenerRequest request = null; HttpListenerResponse response = null; try { var context = state as HttpListenerContext; // request = context.Request; response = context.Response; // if (request.UserLanguages != null && request.UserLanguages.Length > 0) { try { CultureInfo culture = CultureInfo.CreateSpecificCulture(request.UserLanguages[0].ToLowerInvariant().Trim()); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } catch { } } // if (request.IsSecureConnection) { var clientCertificate = request.GetClientCertificate(); var chain = new X509Chain { ChainPolicy = { RevocationMode = X509RevocationMode.NoCheck } }; chain.Build(clientCertificate); if (chain.ChainStatus.Length != 0) { // Invalid certificate response.StatusCode = (int)HttpStatusCode.Unauthorized; response.OutputStream.Close(); return; } } // response.Headers.Set(HttpResponseHeader.Server, "MIG WebService Gateway"); response.KeepAlive = false; // bool requestHasAuthorizationHeader = request.Headers["Authorization"] != null; string remoteAddress = request.RemoteEndPoint.Address.ToString(); string logExtras = ""; // if (servicePassword == "" || requestHasAuthorizationHeader) //request.IsAuthenticated) { bool verified = false; // string authUser = ""; string authPass = ""; // //NOTE: context.User.Identity and request.IsAuthenticated //aren't working under MONO with this code =/ //so we proceed by manually parsing Authorization header // //HttpListenerBasicIdentity identity = null; // if (requestHasAuthorizationHeader) { //identity = (HttpListenerBasicIdentity)context.User.Identity; // authuser = identity.Name; // authpass = identity.Password; byte[] encodedDataAsBytes = Convert.FromBase64String(request.Headers["Authorization"].Split(' ')[1]); string authtoken = Encoding.UTF8.GetString(encodedDataAsBytes); authUser = authtoken.Split(':')[0]; authPass = authtoken.Split(':')[1]; } // //TODO: complete authorization (for now with one fixed user 'admin', add multiuser support) // if (servicePassword == "" || authUser == serviceUsername && Utility.Encryption.SHA1.GenerateHashString(authPass) == servicePassword) { verified = true; } // if (verified) { string url = request.RawUrl.TrimStart('/').TrimStart('\\').TrimStart('.'); if (url.IndexOf("?") > 0) { url = url.Substring(0, url.IndexOf("?")); } // Check if this url is an alias url = UrlAliasCheck(url.TrimEnd('/')); // // url aliasing check if (url == "" || url.TrimEnd('/') == baseUrl.TrimEnd('/')) { // default home redirect response.Redirect("/" + baseUrl.TrimEnd('/') + "/index.html"); //TODO: find a solution for HG homepage redirect ---> ?" + new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds + "#page_control"); response.Close(); } else { var connectionWatch = Stopwatch.StartNew(); MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod, $"{response.StatusCode} {request.RawUrl} [OPEN]")); // this url is reserved for Server Sent Event stream if (url.TrimEnd('/').Equals("events")) { HandleEventsRoute(request, response, context, remoteAddress); } else { try { MigClientRequest migRequest = null; if (url.StartsWith("api/")) { string message = url.Substring(url.IndexOf('/', 1) + 1); var migContext = new MigContext(ContextSource.WebServiceGateway, context); migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(message)); // Disable HTTP caching response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); // Store POST data (if any) in the migRequest.RequestData field migRequest.RequestData = WebServiceUtility.ReadToEnd(request.InputStream); migRequest.RequestText = request.ContentEncoding.GetString(migRequest.RequestData); } OnPreProcessRequest(migRequest); bool requestHandled = migRequest != null && migRequest.Handled; if (requestHandled) { SendResponseObject(context, migRequest.ResponseData); } else if (url.StartsWith(baseUrl) || baseUrl.Equals("/")) { // If request begins <base_url>, process as standard Web request string requestedFile = GetWebFilePath(url); if (!File.Exists(requestedFile)) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, $"<h1>404 - Not Found</h1><br/>{requestedFile}"); } else { bool isText = false; if (url.ToLower().EndsWith(".js")) // || requestedurl.EndsWith(".json")) { response.ContentType = "text/javascript"; isText = true; } else if (url.ToLower().EndsWith(".css")) { response.ContentType = "text/css"; isText = true; } else if (url.ToLower().EndsWith(".zip")) { response.ContentType = "application/zip"; } else if (url.ToLower().EndsWith(".png")) { response.ContentType = "image/png"; } else if (url.ToLower().EndsWith(".jpg")) { response.ContentType = "image/jpeg"; } else if (url.ToLower().EndsWith(".gif")) { response.ContentType = "image/gif"; } else if (url.ToLower().EndsWith(".svg")) { response.ContentType = "image/svg+xml"; } else if (url.ToLower().EndsWith(".mp3")) { response.ContentType = "audio/mp3"; } else if (url.ToLower().EndsWith(".wav")) { response.ContentType = "audio/x-wav"; } else if (url.ToLower().EndsWith(".appcache")) { response.ContentType = "text/cache-manifest"; } else if (url.ToLower().EndsWith(".otf") || url.ToLower().EndsWith(".ttf") || url.ToLower().EndsWith(".woff") || url.ToLower().EndsWith(".woff2")) { response.ContentType = "application/octet-stream"; } else if (url.ToLower().EndsWith(".xml")) { response.ContentType = "text/xml"; isText = true; } else { response.ContentType = "text/html"; isText = true; } var file = new FileInfo(requestedFile); response.ContentLength64 = file.Length; bool modified = true; if (request.Headers.AllKeys.Contains("If-Modified-Since")) { var modifiedSince = DateTime.MinValue; DateTime.TryParse(request.Headers["If-Modified-Since"], out modifiedSince); if (file.LastWriteTime.ToUniversalTime().Equals(modifiedSince)) { modified = false; } } bool disableCacheControl = HttpCacheIgnoreCheck(url); if (!modified && !disableCacheControl) { // TODO: !IMPORTANT! exclude from caching files that contains SSI tags! response.StatusCode = (int)HttpStatusCode.NotModified; //!!DISABLED!! - The following line was preventing browser to load file from cache //response.Headers.Set(HttpResponseHeader.Date, file.LastWriteTimeUtc.ToString().Replace(",", ".")); } else { response.Headers.Set(HttpResponseHeader.LastModified, file.LastWriteTimeUtc.ToString().Replace(",", ".")); if (disableCacheControl) { response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); } else { response.Headers.Set(HttpResponseHeader.CacheControl, "max-age=86400"); } // PRE PROCESS text output if (isText) { try { WebFile webFile = GetWebFile(requestedFile); response.ContentEncoding = webFile.Encoding; response.ContentType += "; charset=" + webFile.Encoding.BodyName; // We don't need to parse the content again if it's coming from the cache if (!webFile.IsCached) { string body = webFile.Content; if (requestedFile.EndsWith(".md")) { // Built-in Markdown files support body = CommonMarkConverter.Convert(body); // TODO: add a way to include HTML header and footer template to be appended to the // TODO: translated markdown text } else { // HTML file // replace prepocessor directives with values bool tagFound; do { tagFound = false; var ts = body.IndexOf("{include "); if (ts >= 0) { var te = body.IndexOf("}", ts); if (te > ts) { var rs = body.Substring(ts + (te - ts) + 1); var cs = body.Substring(ts, te - ts + 1); var ls = body.Substring(0, ts); // try { if (cs.StartsWith("{include ")) { var fileName = cs.Substring(9).TrimEnd('}').Trim(); fileName = GetWebFilePath(fileName); var fileEncoding = DetectWebFileEncoding(fileName) ?? defaultWebFileEncoding; var incFile = File.ReadAllText(fileName, fileEncoding) + rs; body = ls + incFile; } } catch { body = ls + "<h5 style=\"color:red\">Error processing '" + cs.Replace("{", "[").Replace("}", "]") + "'</h5>" + rs; } tagFound = true; } } } while (tagFound); // continue if a pre processor tag was found // {hostos} body = body.Replace("{hostos}", Environment.OSVersion.Platform.ToString()); // {filebase} body = body.Replace("{filebase}", Path.GetFileNameWithoutExtension(requestedFile)); } // update the cache content with parsing results webFile.Content = body; } // Store the cache item if the file cache is enabled if (enableFileCache) { UpdateWebFileCache(requestedFile, webFile.Content, response.ContentEncoding); } // WebServiceUtility.WriteStringToContext(context, webFile.Content); } catch (Exception ex) { // TODO: report internal mig interface error response.StatusCode = (int)HttpStatusCode.InternalServerError; WebServiceUtility.WriteStringToContext(context, ex.Message + "\n" + ex.StackTrace); MigService.Log.Error(ex); } } else { WebServiceUtility.WriteBytesToContext(context, File.ReadAllBytes(requestedFile)); } } } requestHandled = true; } OnPostProcessRequest(migRequest); if (!requestHandled && migRequest != null && migRequest.Handled) { SendResponseObject(context, migRequest.ResponseData); } else if (!requestHandled) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, "<h1>404 - Not Found</h1>"); } } catch (Exception eh) { // TODO: add error logging Console.Error.WriteLine(eh); } } connectionWatch.Stop(); logExtras = " [CLOSED AFTER " + Math.Round(connectionWatch.Elapsed.TotalSeconds, 3) + " seconds]"; } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; // this will only work in Linux (mono) //response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); // this works both on Linux and Windows response.AddHeader("WWW-Authenticate", "Basic realm=\"User Visible Realm\""); } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; // this will only work in Linux (mono) //response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); // this works both on Linux and Windows response.AddHeader("WWW-Authenticate", "Basic realm=\"User Visible Realm\""); } MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod, $"{response.StatusCode} {request.RawUrl}{logExtras}")); } catch (Exception ex) { MigService.Log.Error(ex); } finally { // // CleanUp/Dispose allocated resources // try { request.InputStream.Close(); } catch { // TODO: add logging } try { response.OutputStream.Close(); } catch { // TODO: add logging } try { response.Close(); } catch { // TODO: add logging } try { response.Abort(); } catch { // TODO: add logging } } }
public void ProcessRequest(MigClientRequest request) { var migCommand = request.Command; string streamContent = ""; ProgramBlock currentProgram; ProgramBlock newProgram; string sketchFile = "", sketchFolder = ""; // homegenie.ExecuteAutomationRequest(migCommand); if (migCommand.Command.StartsWith("Macro.")) { switch (migCommand.Command) { case "Macro.Record": homegenie.ProgramManager.MacroRecorder.RecordingEnable(); break; case "Macro.Save": newProgram = homegenie.ProgramManager.MacroRecorder.SaveMacro(migCommand.GetOption(1)); request.ResponseData = newProgram.Address.ToString(); break; case "Macro.Discard": homegenie.ProgramManager.MacroRecorder.RecordingDisable(); break; case "Macro.SetDelay": switch (migCommand.GetOption(0).ToLower()) { case "none": homegenie.ProgramManager.MacroRecorder.DelayType = MacroDelayType.None; break; case "mimic": homegenie.ProgramManager.MacroRecorder.DelayType = MacroDelayType.Mimic; break; case "fixed": double secs = double.Parse( migCommand.GetOption(1), System.Globalization.CultureInfo.InvariantCulture ); homegenie.ProgramManager.MacroRecorder.DelayType = MacroDelayType.Fixed; homegenie.ProgramManager.MacroRecorder.DelaySeconds = secs; break; } break; case "Macro.GetDelay": request.ResponseData = "{ \"DelayType\" : \"" + homegenie.ProgramManager.MacroRecorder.DelayType + "\", \"DelayOptions\" : \"" + homegenie.ProgramManager.MacroRecorder.DelaySeconds + "\" }"; break; } } else if (migCommand.Command.StartsWith("Scheduling.")) { switch (migCommand.Command) { case "Scheduling.Add": case "Scheduling.Update": var newSchedule = JsonConvert.DeserializeObject <SchedulerItem>(request.RequestText); var item = homegenie.ProgramManager.SchedulerService.AddOrUpdate( newSchedule.Name, newSchedule.CronExpression, newSchedule.Data, newSchedule.Description, newSchedule.Script ); if (newSchedule.BoundDevices != null) { item.BoundDevices = newSchedule.BoundDevices; } if (newSchedule.BoundModules != null) { item.BoundModules = newSchedule.BoundModules; } homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Delete": homegenie.ProgramManager.SchedulerService.Remove(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Enable": homegenie.ProgramManager.SchedulerService.Enable(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Disable": homegenie.ProgramManager.SchedulerService.Disable(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Get": request.ResponseData = homegenie.ProgramManager.SchedulerService.Get(migCommand.GetOption(0)); break; case "Scheduling.ListOccurrences": int hours = 24; int.TryParse(migCommand.GetOption(0), out hours); DateTime dateStart = DateTime.Today.ToUniversalTime(); string startFrom = migCommand.GetOption(1); if (!String.IsNullOrWhiteSpace(startFrom)) { dateStart = Utility.JavascriptToDate(long.Parse(startFrom)); } List <dynamic> nextList = new List <dynamic>(); foreach (var ce in homegenie.ProgramManager.SchedulerService.Items) { if (!ce.IsEnabled) { continue; } var evt = new { Name = ce.Name, Description = ce.Description, RunScript = !String.IsNullOrWhiteSpace(ce.Script), Occurrences = new List <double>() }; var d = dateStart; var dateEnd = dateStart.AddHours(hours); var occurs = homegenie.ProgramManager.SchedulerService.GetScheduling(dateStart, dateEnd, ce.CronExpression); occurs.Sort(); foreach (var dt in occurs) { evt.Occurrences.Add(Utility.DateToJavascript(dt.ToUniversalTime())); } if (evt.Occurrences.Count > 0) { nextList.Add(evt); } } request.ResponseData = nextList; break; case "Scheduling.List": homegenie.ProgramManager.SchedulerService.Items.Sort((SchedulerItem s1, SchedulerItem s2) => { return(s1.Name.CompareTo(s2.Name)); }); request.ResponseData = homegenie.ProgramManager.SchedulerService.Items; break; case "Scheduling.Describe": var cronDescription = ""; try { cronDescription = ExpressionDescriptor.GetDescription(migCommand.GetOption(0).Trim()); cronDescription = Char.ToLowerInvariant(cronDescription[0]) + cronDescription.Substring(1); } catch { } request.ResponseData = new ResponseText(cronDescription); break; case "Scheduling.SolarTimes": var solarTimes = new SolarTimes(DateTime.Now, homegenie.ProgramManager.SchedulerService.Location["latitude"].Value, homegenie.ProgramManager.SchedulerService.Location["longitude"].Value); request.ResponseData = solarTimes; break; } } else if (migCommand.Command.StartsWith("Programs.")) { if (migCommand.Command != "Programs.Import") { streamContent = request.RequestText; } // switch (migCommand.Command) { case "Programs.Import": string archiveName = "homegenie_program_import.hgx"; if (File.Exists(archiveName)) { File.Delete(archiveName); } // MIG.Gateways.WebServiceUtility.SaveFile(request.RequestData, archiveName); int newPid = homegenie.ProgramManager.GeneratePid(); newProgram = homegenie.PackageManager.ProgramImport(newPid, archiveName, migCommand.GetOption(0)); /* * int newPid = homegenie.ProgramManager.GeneratePid(); * var reader = new StreamReader(archiveName); * char[] signature = new char[2]; * reader.Read(signature, 0, 2); * reader.Close(); * if (signature[0] == 'P' && signature[1] == 'K') * { * // Read and uncompress zip file content (arduino program bundle) * string zipFileName = archiveName.Replace(".hgx", ".zip"); * if (File.Exists(zipFileName)) * File.Delete(zipFileName); * File.Move(archiveName, zipFileName); * string destFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Utility.GetTmpFolder(), "import"); * if (Directory.Exists(destFolder)) * Directory.Delete(destFolder, true); * Utility.UncompressZip(zipFileName, destFolder); * string bundleFolder = Path.Combine("programs", "arduino", newPid.ToString()); * if (Directory.Exists(bundleFolder)) * Directory.Delete(bundleFolder, true); * if (!Directory.Exists(Path.Combine("programs", "arduino"))) * Directory.CreateDirectory(Path.Combine("programs", "arduino")); * Directory.Move(Path.Combine(destFolder, "src"), bundleFolder); * reader = new StreamReader(Path.Combine(destFolder, "program.hgx")); * } * else * { * reader = new StreamReader(archiveName); * } * var serializer = new XmlSerializer(typeof(ProgramBlock)); * newProgram = (ProgramBlock)serializer.Deserialize(reader); * reader.Close(); * // * newProgram.Address = newPid; * newProgram.Group = migCommand.GetOption(0); * homegenie.ProgramManager.ProgramAdd(newProgram); * // * newProgram.IsEnabled = false; * newProgram.ScriptErrors = ""; * newProgram.Engine.SetHost(homegenie); * // * if (newProgram.Type.ToLower() != "arduino") * { * homegenie.ProgramManager.CompileScript(newProgram); * } */ homegenie.UpdateProgramsDatabase(); //migCommand.response = JsonHelper.GetSimpleResponse(programblock.Address); request.ResponseData = newProgram.Address.ToString(); break; case "Programs.Export": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); string filename = currentProgram.Address + "-" + currentProgram.Name.Replace(" ", "_"); // var writerSettings = new System.Xml.XmlWriterSettings(); writerSettings.Indent = true; writerSettings.Encoding = Encoding.UTF8; var programSerializer = new System.Xml.Serialization.XmlSerializer(typeof(ProgramBlock)); var builder = new StringBuilder(); var writer = System.Xml.XmlWriter.Create(builder, writerSettings); programSerializer.Serialize(writer, currentProgram); writer.Close(); // if (currentProgram.Type.ToLower() == "arduino") { string arduinoBundle = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Utility.GetTmpFolder(), "export", filename + ".zip"); if (File.Exists(arduinoBundle)) { File.Delete(arduinoBundle); } else if (!Directory.Exists(Path.GetDirectoryName(arduinoBundle))) { Directory.CreateDirectory(Path.GetDirectoryName(arduinoBundle)); } string mainProgramFile = Path.Combine(Path.GetDirectoryName(arduinoBundle), "program.hgx"); File.WriteAllText( mainProgramFile, builder.ToString() ); Utility.AddFileToZip(arduinoBundle, mainProgramFile, "program.hgx"); sketchFolder = Path.Combine("programs", "arduino", currentProgram.Address.ToString()); foreach (string f in Directory.GetFiles(sketchFolder)) { if (!Path.GetFileName(f).StartsWith("sketch_")) { Utility.AddFileToZip( arduinoBundle, Path.Combine(sketchFolder, Path.GetFileName(f)), Path.Combine( "src", Path.GetFileName(f) ) ); } } // byte[] bundleData = File.ReadAllBytes(arduinoBundle); (request.Context.Data as HttpListenerContext).Response.AddHeader( "Content-Disposition", "attachment; filename=\"" + filename + ".zip\"" ); (request.Context.Data as HttpListenerContext).Response.OutputStream.Write(bundleData, 0, bundleData.Length); } else { (request.Context.Data as HttpListenerContext).Response.AddHeader( "Content-Disposition", "attachment; filename=\"" + filename + ".hgx\"" ); request.ResponseData = builder.ToString(); } break; case "Programs.List": var programList = new List <ProgramBlock>(homegenie.ProgramManager.Programs); programList.Sort(delegate(ProgramBlock p1, ProgramBlock p2) { string c1 = p1.Name + " " + p1.Address; string c2 = p2.Name + " " + p2.Address; return(c1.CompareTo(c2)); }); request.ResponseData = programList; break; case "Programs.Get": try { var prg = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); var settings = new JsonSerializerSettings { Formatting = Formatting.Indented }; request.ResponseData = JsonConvert.SerializeObject(prg, settings); } catch (Exception ex) { request.ResponseData = new ResponseText("ERROR: \n" + ex.Message + "\n\n" + ex.StackTrace); } break; case "Programs.Add": newProgram = new ProgramBlock() { Group = migCommand.GetOption(0), Name = streamContent, Type = "Wizard" }; newProgram.Address = homegenie.ProgramManager.GeneratePid(); homegenie.ProgramManager.ProgramAdd(newProgram); homegenie.UpdateProgramsDatabase(); request.ResponseData = new ResponseText(newProgram.Address.ToString()); break; case "Programs.Delete": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { //TODO: remove groups associations as well homegenie.ProgramManager.ProgramRemove(currentProgram); homegenie.UpdateProgramsDatabase(); // remove associated module entry homegenie.Modules.RemoveAll(m => m.Domain == Domains.HomeAutomation_HomeGenie_Automation && m.Address == currentProgram.Address.ToString()); homegenie.UpdateModulesDatabase(); } break; case "Programs.Compile": case "Programs.Update": newProgram = JsonConvert.DeserializeObject <ProgramBlock>(streamContent); currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == newProgram.Address); // if (currentProgram == null) { newProgram.Address = homegenie.ProgramManager.GeneratePid(); homegenie.ProgramManager.ProgramAdd(newProgram); } else { bool typeChanged = (currentProgram.Type.ToLower() != newProgram.Type.ToLower()); currentProgram.Type = newProgram.Type; currentProgram.Group = newProgram.Group; currentProgram.Name = newProgram.Name; currentProgram.Description = newProgram.Description; if (typeChanged) { currentProgram.Engine.SetHost(homegenie); } currentProgram.IsEnabled = newProgram.IsEnabled; currentProgram.ScriptCondition = newProgram.ScriptCondition; currentProgram.ScriptSource = newProgram.ScriptSource; currentProgram.Commands = newProgram.Commands; currentProgram.Conditions = newProgram.Conditions; currentProgram.ConditionType = newProgram.ConditionType; // reset last condition evaluation status currentProgram.LastConditionEvaluationResult = false; } // if (migCommand.Command == "Programs.Compile") { // reset previous error status currentProgram.IsEnabled = false; currentProgram.Engine.StopProgram(); currentProgram.ScriptErrors = ""; // List <ProgramError> errors = homegenie.ProgramManager.CompileScript(currentProgram); // currentProgram.IsEnabled = newProgram.IsEnabled && errors.Count == 0; currentProgram.ScriptErrors = JsonConvert.SerializeObject(errors); request.ResponseData = currentProgram.ScriptErrors; } // homegenie.UpdateProgramsDatabase(); // homegenie.modules_RefreshPrograms(); homegenie.modules_RefreshVirtualModules(); homegenie.modules_Sort(); break; case "Programs.Arduino.FileLoad": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); sketchFile = migCommand.GetOption(1); if (sketchFile == "main") { // "main" is a special keyword to indicate the main program sketch file sketchFile = ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0)); } sketchFile = Path.Combine(sketchFolder, Path.GetFileName(sketchFile)); request.ResponseData = new ResponseText(File.ReadAllText(sketchFile)); break; case "Programs.Arduino.FileSave": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); sketchFile = Path.Combine(sketchFolder, Path.GetFileName(migCommand.GetOption(1))); File.WriteAllText(sketchFile, streamContent); break; case "Programs.Arduino.FileAdd": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); if (!Directory.Exists(sketchFolder)) { Directory.CreateDirectory(sketchFolder); } sketchFile = Path.Combine(sketchFolder, Path.GetFileName(migCommand.GetOption(1))); if (File.Exists(sketchFile)) { request.ResponseData = new ResponseText("EXISTS"); } else if (!ArduinoAppFactory.IsValidProjectFile(sketchFile)) { request.ResponseData = new ResponseText("INVALID_NAME"); } else { StreamWriter sw = File.CreateText(sketchFile); sw.Close(); sw.Dispose(); sw = null; request.ResponseData = new ResponseText("OK"); } break; case "Programs.Arduino.FileDelete": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); sketchFile = Path.Combine(sketchFolder, Path.GetFileName(migCommand.GetOption(1))); if (!File.Exists(sketchFile)) { request.ResponseData = new ResponseText("NOT_FOUND"); } else { File.Delete(sketchFile); request.ResponseData = new ResponseText("OK"); } break; case "Programs.Arduino.FileList": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); List <string> files = new List <string>(); foreach (string f in Directory.GetFiles(sketchFolder)) { if (ArduinoAppFactory.IsValidProjectFile(f)) { files.Add(Path.GetFileName(f)); } } request.ResponseData = files; break; case "Programs.Run": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { // clear any runtime errors before running currentProgram.ScriptErrors = ""; homegenie.ProgramManager.RaiseProgramModuleEvent( currentProgram, Properties.RuntimeError, "" ); currentProgram.IsEnabled = true; System.Threading.Thread.Sleep(500); ProgramRun(migCommand.GetOption(0), migCommand.GetOption(1)); } break; case "Programs.Toggle": currentProgram = ProgramToggle(migCommand.GetOption(0), migCommand.GetOption(1)); break; case "Programs.Break": currentProgram = ProgramBreak(migCommand.GetOption(0)); break; case "Programs.Restart": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { currentProgram.IsEnabled = false; try { currentProgram.Engine.StopProgram(); } catch { } currentProgram.IsEnabled = true; homegenie.UpdateProgramsDatabase(); } break; case "Programs.Enable": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { currentProgram.IsEnabled = true; homegenie.UpdateProgramsDatabase(); } break; case "Programs.Disable": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { currentProgram.IsEnabled = false; try { currentProgram.Engine.StopProgram(); } catch { } homegenie.UpdateProgramsDatabase(); } break; } } }
protected virtual void OnPreProcessRequest(MigClientRequest request) { if (request != null && PreProcessRequest != null) PreProcessRequest(this, new ProcessRequestEventArgs(request)); }
public void ProcessRequest(MessageEventArgs args) { var migContext = new MigContext(ContextSource.WebSocketGateway, args); var migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(args.Data)); OnPreProcessRequest(migRequest); if (!migRequest.Handled) OnPostProcessRequest(migRequest); }
private void Worker(object state) { HttpListenerRequest request = null; HttpListenerResponse response = null; try { var context = state as HttpListenerContext; // request = context.Request; response = context.Response; // if (request.UserLanguages != null && request.UserLanguages.Length > 0) { try { CultureInfo culture = CultureInfo.CreateSpecificCulture(request.UserLanguages[0].ToLowerInvariant().Trim()); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } catch { } } // if (request.IsSecureConnection) { var clientCertificate = request.GetClientCertificate(); X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(clientCertificate); if (chain.ChainStatus.Length != 0) { // Invalid certificate response.StatusCode = (int)HttpStatusCode.Unauthorized; response.OutputStream.Close(); return; } } // response.Headers.Set(HttpResponseHeader.Server, "MIG WebService Gateway"); response.KeepAlive = false; // bool isAuthenticated = (request.Headers["Authorization"] != null); string remoteAddress = request.RemoteEndPoint.Address.ToString(); // if (servicePassword == "" || isAuthenticated) //request.IsAuthenticated) { bool verified = false; // string authUser = ""; string authPass = ""; // //NOTE: context.User.Identity and request.IsAuthenticated //aren't working under MONO with this code =/ //so we proceed by manually parsing Authorization header // //HttpListenerBasicIdentity identity = null; // if (isAuthenticated) { //identity = (HttpListenerBasicIdentity)context.User.Identity; // authuser = identity.Name; // authpass = identity.Password; byte[] encodedDataAsBytes = System.Convert.FromBase64String(request.Headers["Authorization"].Split(' ')[1]); string authtoken = System.Text.Encoding.UTF8.GetString(encodedDataAsBytes); authUser = authtoken.Split(':')[0]; authPass = authtoken.Split(':')[1]; } // //TODO: complete authorization (for now with one fixed user 'admin', add multiuser support) // if (servicePassword == "" || (authUser == serviceUsername && Utility.Encryption.SHA1.GenerateHashString(authPass) == servicePassword)) { verified = true; } // if (verified) { string url = request.RawUrl.TrimStart('/').TrimStart('\\').TrimStart('.'); if (url.IndexOf("?") > 0) url = url.Substring(0, url.IndexOf("?")); // Check if this url is an alias url = UrlAliasCheck(url.TrimEnd('/')); // // url aliasing check if (url == "" || url.TrimEnd('/') == baseUrl.TrimEnd('/')) { // default home redirect response.Redirect("/" + baseUrl.TrimEnd('/') + "/index.html"); //TODO: find a solution for HG homepage redirect ---> ?" + new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds + "#page_control"); response.Close(); } else { // this url is reserved for Server Sent Event stream if (url.TrimEnd('/').Equals("events")) { // Server sent events MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1}", response.StatusCode, request.RawUrl))); // NOTE: no PreProcess or PostProcess events are fired in this case //response.KeepAlive = true; response.ContentEncoding = Encoding.UTF8; response.ContentType = "text/event-stream"; response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache"); response.Headers.Set("Access-Control-Allow-Origin", "*"); // 2K padding for IE var padding = ":" + new String(' ', 2048) + "\n"; byte[] paddingData = System.Text.Encoding.UTF8.GetBytes(padding); response.OutputStream.Write(paddingData, 0, paddingData.Length); byte[] retryData = System.Text.Encoding.UTF8.GetBytes("retry: 1000\n"); response.OutputStream.Write(retryData, 0, retryData.Length); response.OutputStream.Flush(); bool connected = true; InterfacePropertyChangedEventHandler changedDelegate = (object sender, InterfacePropertyChangedEventArgs args) => { try { lock (response) { // TODO: event data should not contains \n character, so these should be stripped or escaped byte[] data = System.Text.Encoding.UTF8.GetBytes("id: " + args.EventData.Timestamp.Ticks + "\ndata: " + MigService.JsonSerialize(args.EventData) + "\n\n"); response.OutputStream.Write(data, 0, data.Length); response.OutputStream.Flush(); } } catch (Exception e) { // Client disconnected //MigService.Log.Error(e); connected = false; } }; this.PropertyChanged += changedDelegate; while (connected) { Thread.Sleep(1000); } this.PropertyChanged -= changedDelegate; return; } else { try { MigClientRequest migRequest = null; if (url.StartsWith("api/")) { string message = url.Substring(url.IndexOf('/', 1) + 1); var migContext = new MigContext(ContextSource.WebServiceGateway, context); migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(message)); // Disable HTTP caching response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); // Store POST data (if any) in the migRequest.RequestData field migRequest.RequestData = WebServiceUtility.ReadToEnd(request.InputStream); migRequest.RequestText = request.ContentEncoding.GetString(migRequest.RequestData); } OnPreProcessRequest(migRequest); bool requestHandled = (migRequest != null && migRequest.Handled); if (requestHandled) { SendResponseObject(context, migRequest.ResponseData); } else if (url.StartsWith(baseUrl) || baseUrl.Equals("/")) { // If request begins <base_url>, process as standard Web request string requestedFile = GetWebFilePath(url); if (!System.IO.File.Exists(requestedFile)) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, "<h1>404 - Not Found</h1>"); } else { bool isText = false; if (url.ToLower().EndsWith(".js")) // || requestedurl.EndsWith(".json")) { response.ContentType = "text/javascript"; isText = true; } else if (url.ToLower().EndsWith(".css")) { response.ContentType = "text/css"; isText = true; } else if (url.ToLower().EndsWith(".zip")) { response.ContentType = "application/zip"; } else if (url.ToLower().EndsWith(".png")) { response.ContentType = "image/png"; } else if (url.ToLower().EndsWith(".jpg")) { response.ContentType = "image/jpeg"; } else if (url.ToLower().EndsWith(".gif")) { response.ContentType = "image/gif"; } else if (url.ToLower().EndsWith(".mp3")) { response.ContentType = "audio/mp3"; } else if (url.ToLower().EndsWith(".appcache")) { response.ContentType = "text/cache-manifest"; } else { response.ContentType = "text/html"; isText = true; } var file = new System.IO.FileInfo(requestedFile); bool modified = true; if (request.Headers.AllKeys.Contains("If-Modified-Since")) { var modifiedSince = DateTime.MinValue; DateTime.TryParse(request.Headers["If-Modified-Since"], out modifiedSince); if (file.LastWriteTime.Equals(modifiedSince)) modified = false; } bool disableCacheControl = HttpCacheIgnoreCheck(url); if (!modified && !disableCacheControl) { // TODO: !IMPORTANT! exclude from caching files that contains SSI tags! response.StatusCode = (int)HttpStatusCode.NotModified; response.Headers.Set(HttpResponseHeader.Date, file.LastWriteTimeUtc.ToString("r")); } else { response.Headers.Set(HttpResponseHeader.LastModified, file.LastWriteTimeUtc.ToString("r")); if (disableCacheControl) { response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); } else { response.Headers.Set(HttpResponseHeader.CacheControl, "max-age=86400"); } // PRE PROCESS text output if (isText) { try { WebFile webFile = GetWebFile(requestedFile); response.ContentEncoding = webFile.Encoding; response.ContentType += "; charset=" + webFile.Encoding.BodyName; // We don't need to parse the content again if it's coming from the cache if (!webFile.IsCached) { string body = webFile.Content; if (requestedFile.EndsWith(".md")) { // Built-in Markdown files support body = CommonMark.CommonMarkConverter.Convert(body); // TODO: add a way to include HTML header and footer template to be appended to the // TODO: translated markdown text } else { // HTML file // replace prepocessor directives with values bool tagFound; do { tagFound = false; int ts = body.IndexOf("{include "); if (ts >= 0) { int te = body.IndexOf("}", ts); if (te > ts) { string rs = body.Substring(ts + (te - ts) + 1); string cs = body.Substring(ts, te - ts + 1); string ls = body.Substring(0, ts); // try { if (cs.StartsWith("{include ")) { string fileName = cs.Substring(9).TrimEnd('}').Trim(); fileName = GetWebFilePath(fileName); // Encoding fileEncoding = DetectWebFileEncoding(fileName); if (fileEncoding == null) fileEncoding = defaultWebFileEncoding; var incFile = System.IO.File.ReadAllText(fileName, fileEncoding) + rs; body = ls + incFile; } } catch { body = ls + "<h5 style=\"color:red\">Error processing '" + cs.Replace("{", "[").Replace("}", "]") + "'</h5>" + rs; } tagFound = true; } } } while (tagFound); // continue if a pre processor tag was found // {hostos} body = body.Replace("{hostos}", Environment.OSVersion.Platform.ToString()); // {filebase} body = body.Replace("{filebase}", Path.GetFileNameWithoutExtension(requestedFile)); } // update the cache content with parsing results webFile.Content = body; } // Store the cache item if the file cache is enabled if (enableFileCache) { UpdateWebFileCache(requestedFile, webFile.Content, response.ContentEncoding); } // WebServiceUtility.WriteStringToContext(context, webFile.Content); } catch (Exception ex) { // TODO: report internal mig interface error response.StatusCode = (int)HttpStatusCode.InternalServerError; WebServiceUtility.WriteStringToContext(context, ex.Message + "\n" + ex.StackTrace); MigService.Log.Error(ex); } } else { WebServiceUtility.WriteBytesToContext(context, System.IO.File.ReadAllBytes(requestedFile)); } } } requestHandled = true; } OnPostProcessRequest(migRequest); if (!requestHandled && migRequest != null && migRequest.Handled) { SendResponseObject(context, migRequest.ResponseData); } else if (!requestHandled) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, "<h1>404 - Not Found</h1>"); } } catch (Exception eh) { // TODO: add error logging Console.Error.WriteLine(eh); } } } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); } MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1}", response.StatusCode, request.RawUrl))); } catch (Exception ex) { MigService.Log.Error(ex); } // try { response.OutputStream.Close(); response.Close(); } catch { // TODO: add logging } try { request.InputStream.Close(); } catch { // TODO: add logging } }
private void Worker(object state) { HttpListenerRequest request = null; HttpListenerResponse response = null; try { var context = state as HttpListenerContext; // request = context.Request; response = context.Response; // if (request.UserLanguages != null && request.UserLanguages.Length > 0) { try { CultureInfo culture = CultureInfo.CreateSpecificCulture(request.UserLanguages[0].ToLowerInvariant().Trim()); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } catch { } } // if (request.IsSecureConnection) { var clientCertificate = request.GetClientCertificate(); X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(clientCertificate); if (chain.ChainStatus.Length != 0) { // Invalid certificate response.StatusCode = (int)HttpStatusCode.Unauthorized; response.OutputStream.Close(); return; } } // response.Headers.Set(HttpResponseHeader.Server, "MIG WebService Gateway"); response.KeepAlive = false; // bool isAuthenticated = (request.Headers["Authorization"] != null); string remoteAddress = request.RemoteEndPoint.Address.ToString(); string logExtras = ""; // if (servicePassword == "" || isAuthenticated) //request.IsAuthenticated) { bool verified = false; // string authUser = ""; string authPass = ""; // //NOTE: context.User.Identity and request.IsAuthenticated //aren't working under MONO with this code =/ //so we proceed by manually parsing Authorization header // //HttpListenerBasicIdentity identity = null; // if (isAuthenticated) { //identity = (HttpListenerBasicIdentity)context.User.Identity; // authuser = identity.Name; // authpass = identity.Password; byte[] encodedDataAsBytes = System.Convert.FromBase64String(request.Headers["Authorization"].Split(' ')[1]); string authtoken = System.Text.Encoding.UTF8.GetString(encodedDataAsBytes); authUser = authtoken.Split(':')[0]; authPass = authtoken.Split(':')[1]; } // //TODO: complete authorization (for now with one fixed user 'admin', add multiuser support) // if (servicePassword == "" || (authUser == serviceUsername && Utility.Encryption.SHA1.GenerateHashString(authPass) == servicePassword)) { verified = true; } // if (verified) { string url = request.RawUrl.TrimStart('/').TrimStart('\\').TrimStart('.'); if (url.IndexOf("?") > 0) { url = url.Substring(0, url.IndexOf("?")); } // Check if this url is an alias url = UrlAliasCheck(url.TrimEnd('/')); // // url aliasing check if (url == "" || url.TrimEnd('/') == baseUrl.TrimEnd('/')) { // default home redirect response.Redirect("/" + baseUrl.TrimEnd('/') + "/index.html"); //TODO: find a solution for HG homepage redirect ---> ?" + new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds + "#page_control"); response.Close(); } else { var connectionWatch = Stopwatch.StartNew(); MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1} [OPEN]", response.StatusCode, request.RawUrl))); // this url is reserved for Server Sent Event stream if (url.TrimEnd('/').Equals("events")) { // TODO: move all of this to a separate function // Server sent events // NOTE: no PreProcess or PostProcess events are fired in this case //response.KeepAlive = true; response.ContentEncoding = Encoding.UTF8; response.ContentType = "text/event-stream"; response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set("Access-Control-Allow-Origin", "*"); // 2K padding for IE var padding = ":" + new String(' ', 2048) + "\n"; byte[] paddingData = System.Text.Encoding.UTF8.GetBytes(padding); response.OutputStream.Write(paddingData, 0, paddingData.Length); byte[] retryData = System.Text.Encoding.UTF8.GetBytes("retry: 1000\n"); response.OutputStream.Write(retryData, 0, retryData.Length); DateTime lastTimeStamp = DateTime.UtcNow; var lastId = context.Request.Headers.Get("Last-Event-ID"); if (lastId == null || lastId == "") { var queryValues = HttpUtility.ParseQueryString(context.Request.Url.Query); lastId = queryValues.Get("lastEventId"); } if (lastId != null && lastId != "") { double unixTimestamp = 0; double.TryParse(lastId, NumberStyles.Float | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out unixTimestamp); if (unixTimestamp != 0) { lastTimeStamp = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); lastTimeStamp.AddSeconds(Math.Round(unixTimestamp / 1000d)); } } bool connected = true; var timeoutWatch = Stopwatch.StartNew(); while (connected) { // dirty work around for signaling new event and // avoiding locks on long socket timetout lock (sseEventToken) Monitor.Wait(sseEventToken, 1000); // safely dequeue events List <SseEvent> bufferedData; do { bufferedData = sseEventBuffer.FindAll(le => le != null && le.Timestamp.Ticks > lastTimeStamp.Ticks); if (bufferedData.Count > 0) { foreach (SseEvent entry in bufferedData) { // send events try { // The following throws an error on some mono-arm (Input string was not in the correct format) // entry.Event.UnixTimestamp.ToString("R", CultureInfo.InvariantCulture) byte[] data = System.Text.Encoding.UTF8.GetBytes("id: " + entry.Event.UnixTimestamp.ToString().Replace(",", ".") + "\ndata: " + MigService.JsonSerialize(entry.Event) + "\n\n"); response.OutputStream.Write(data, 0, data.Length); //response.OutputStream.Flush(); lastTimeStamp = entry.Timestamp; } catch (Exception e) { MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1} [ERROR: {2}]", response.StatusCode, request.RawUrl, e.Message))); connected = false; break; } } Thread.Sleep(100); } // there might be new data after sending } while (connected && bufferedData.Count > 0); // check if the remote end point is still alive every 15 seconds or so if (timeoutWatch.Elapsed.TotalSeconds > 15) { connected = connected && IsRemoteEndPointConnected(request.RemoteEndPoint); timeoutWatch.Stop(); timeoutWatch = Stopwatch.StartNew(); } } } else { try { MigClientRequest migRequest = null; if (url.StartsWith("api/")) { string message = url.Substring(url.IndexOf('/', 1) + 1); var migContext = new MigContext(ContextSource.WebServiceGateway, context); migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(message)); // Disable HTTP caching response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); // Store POST data (if any) in the migRequest.RequestData field migRequest.RequestData = WebServiceUtility.ReadToEnd(request.InputStream); migRequest.RequestText = request.ContentEncoding.GetString(migRequest.RequestData); } OnPreProcessRequest(migRequest); bool requestHandled = (migRequest != null && migRequest.Handled); if (requestHandled) { SendResponseObject(context, migRequest.ResponseData); } else if (url.StartsWith(baseUrl) || baseUrl.Equals("/")) { // If request begins <base_url>, process as standard Web request string requestedFile = GetWebFilePath(url); if (!System.IO.File.Exists(requestedFile)) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, "<h1>404 - Not Found</h1>"); } else { bool isText = false; if (url.ToLower().EndsWith(".js")) // || requestedurl.EndsWith(".json")) { response.ContentType = "text/javascript"; isText = true; } else if (url.ToLower().EndsWith(".css")) { response.ContentType = "text/css"; isText = true; } else if (url.ToLower().EndsWith(".zip")) { response.ContentType = "application/zip"; } else if (url.ToLower().EndsWith(".png")) { response.ContentType = "image/png"; } else if (url.ToLower().EndsWith(".jpg")) { response.ContentType = "image/jpeg"; } else if (url.ToLower().EndsWith(".gif")) { response.ContentType = "image/gif"; } else if (url.ToLower().EndsWith(".svg")) { response.ContentType = "image/svg+xml"; } else if (url.ToLower().EndsWith(".mp3")) { response.ContentType = "audio/mp3"; } else if (url.ToLower().EndsWith(".wav")) { response.ContentType = "audio/x-wav"; } else if (url.ToLower().EndsWith(".appcache")) { response.ContentType = "text/cache-manifest"; } else if (url.ToLower().EndsWith(".otf") || url.ToLower().EndsWith(".ttf") || url.ToLower().EndsWith(".woff") || url.ToLower().EndsWith(".woff2")) { response.ContentType = "application/octet-stream"; } else if (url.ToLower().EndsWith(".xml")) { response.ContentType = "text/xml"; isText = true; } else { response.ContentType = "text/html"; isText = true; } var file = new System.IO.FileInfo(requestedFile); response.ContentLength64 = file.Length; bool modified = true; if (request.Headers.AllKeys.Contains("If-Modified-Since")) { var modifiedSince = DateTime.MinValue; DateTime.TryParse(request.Headers["If-Modified-Since"], out modifiedSince); if (file.LastWriteTime.ToUniversalTime().Equals(modifiedSince)) { modified = false; } } bool disableCacheControl = HttpCacheIgnoreCheck(url); if (!modified && !disableCacheControl) { // TODO: !IMPORTANT! exclude from caching files that contains SSI tags! response.StatusCode = (int)HttpStatusCode.NotModified; //!!DISABLED!! - The following line was preventing browser to load file from cache //response.Headers.Set(HttpResponseHeader.Date, file.LastWriteTimeUtc.ToString().Replace(",", ".")); } else { response.Headers.Set(HttpResponseHeader.LastModified, file.LastWriteTimeUtc.ToString().Replace(",", ".")); if (disableCacheControl) { response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); } else { response.Headers.Set(HttpResponseHeader.CacheControl, "max-age=86400"); } // PRE PROCESS text output if (isText) { try { WebFile webFile = GetWebFile(requestedFile); response.ContentEncoding = webFile.Encoding; response.ContentType += "; charset=" + webFile.Encoding.BodyName; // We don't need to parse the content again if it's coming from the cache if (!webFile.IsCached) { string body = webFile.Content; if (requestedFile.EndsWith(".md")) { // Built-in Markdown files support body = CommonMark.CommonMarkConverter.Convert(body); // TODO: add a way to include HTML header and footer template to be appended to the // TODO: translated markdown text } else { // HTML file // replace prepocessor directives with values bool tagFound; do { tagFound = false; int ts = body.IndexOf("{include "); if (ts >= 0) { int te = body.IndexOf("}", ts); if (te > ts) { string rs = body.Substring(ts + (te - ts) + 1); string cs = body.Substring(ts, te - ts + 1); string ls = body.Substring(0, ts); // try { if (cs.StartsWith("{include ")) { string fileName = cs.Substring(9).TrimEnd('}').Trim(); fileName = GetWebFilePath(fileName); // Encoding fileEncoding = DetectWebFileEncoding(fileName); if (fileEncoding == null) { fileEncoding = defaultWebFileEncoding; } var incFile = System.IO.File.ReadAllText(fileName, fileEncoding) + rs; body = ls + incFile; } } catch { body = ls + "<h5 style=\"color:red\">Error processing '" + cs.Replace("{", "[").Replace("}", "]") + "'</h5>" + rs; } tagFound = true; } } } while (tagFound); // continue if a pre processor tag was found // {hostos} body = body.Replace("{hostos}", Environment.OSVersion.Platform.ToString()); // {filebase} body = body.Replace("{filebase}", Path.GetFileNameWithoutExtension(requestedFile)); } // update the cache content with parsing results webFile.Content = body; } // Store the cache item if the file cache is enabled if (enableFileCache) { UpdateWebFileCache(requestedFile, webFile.Content, response.ContentEncoding); } // WebServiceUtility.WriteStringToContext(context, webFile.Content); } catch (Exception ex) { // TODO: report internal mig interface error response.StatusCode = (int)HttpStatusCode.InternalServerError; WebServiceUtility.WriteStringToContext(context, ex.Message + "\n" + ex.StackTrace); MigService.Log.Error(ex); } } else { WebServiceUtility.WriteBytesToContext(context, System.IO.File.ReadAllBytes(requestedFile)); } } } requestHandled = true; } OnPostProcessRequest(migRequest); if (!requestHandled && migRequest != null && migRequest.Handled) { SendResponseObject(context, migRequest.ResponseData); } else if (!requestHandled) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, "<h1>404 - Not Found</h1>"); } } catch (Exception eh) { // TODO: add error logging Console.Error.WriteLine(eh); } } connectionWatch.Stop(); logExtras = " [CLOSED AFTER " + Math.Round(connectionWatch.Elapsed.TotalSeconds, 3) + " seconds]"; } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; // this will only work in Linux (mono) //response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); // this works both on Linux and Windows //response.AddHeader("WWW-Authenticate", "Basic"); } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; // this will only work in Linux (mono) //response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); // this works both on Linux and Windows //response.AddHeader("WWW-Authenticate", "Basic"); } MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1}{2}", response.StatusCode, request.RawUrl, logExtras))); } catch (Exception ex) { MigService.Log.Error(ex); } finally { // // CleanUp/Dispose allocated resources // try { request.InputStream.Close(); } catch { // TODO: add logging } try { response.OutputStream.Close(); } catch { // TODO: add logging } try { response.Close(); } catch { // TODO: add logging } try { response.Abort(); } catch { // TODO: add logging } } }
public void ProcessRequest(ServerDataEventArgs args) { UTF8Encoding encoding = new UTF8Encoding(); var message = encoding.GetString(args.Data, 0, args.DataLength); var migContext = new MigContext(ContextSource.TcpSocketGateway, args); var migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(message)); OnPreProcessRequest(migRequest); if (!migRequest.Handled) OnPostProcessRequest(migRequest); }
private void Worker(object state) { HttpListenerRequest request = null; HttpListenerResponse response = null; try { var context = state as HttpListenerContext; // request = context.Request; response = context.Response; // if (request.UserLanguages != null && request.UserLanguages.Length > 0) { try { CultureInfo culture = CultureInfo.CreateSpecificCulture(request.UserLanguages[0].ToLowerInvariant().Trim()); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } catch { } } // if (request.IsSecureConnection) { var clientCertificate = request.GetClientCertificate(); X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(clientCertificate); if (chain.ChainStatus.Length != 0) { // Invalid certificate response.StatusCode = (int)HttpStatusCode.Unauthorized; response.OutputStream.Close(); return; } } // response.Headers.Set(HttpResponseHeader.Server, "MIG WebService Gateway"); response.KeepAlive = false; // bool isAuthenticated = (request.Headers["Authorization"] != null); string remoteAddress = request.RemoteEndPoint.Address.ToString(); string logExtras = ""; // if (servicePassword == "" || isAuthenticated) //request.IsAuthenticated) { bool verified = false; // string authUser = ""; string authPass = ""; // //NOTE: context.User.Identity and request.IsAuthenticated //aren't working under MONO with this code =/ //so we proceed by manually parsing Authorization header // //HttpListenerBasicIdentity identity = null; // if (isAuthenticated) { //identity = (HttpListenerBasicIdentity)context.User.Identity; // authuser = identity.Name; // authpass = identity.Password; byte[] encodedDataAsBytes = System.Convert.FromBase64String(request.Headers["Authorization"].Split(' ')[1]); string authtoken = System.Text.Encoding.UTF8.GetString(encodedDataAsBytes); authUser = authtoken.Split(':')[0]; authPass = authtoken.Split(':')[1]; } // //TODO: complete authorization (for now with one fixed user 'admin', add multiuser support) // if (servicePassword == "" || (authUser == serviceUsername && Utility.Encryption.SHA1.GenerateHashString(authPass) == servicePassword)) { verified = true; } // if (verified) { string url = request.RawUrl.TrimStart('/').TrimStart('\\').TrimStart('.'); if (url.IndexOf("?") > 0) url = url.Substring(0, url.IndexOf("?")); // Check if this url is an alias url = UrlAliasCheck(url.TrimEnd('/')); // // url aliasing check if (url == "" || url.TrimEnd('/') == baseUrl.TrimEnd('/')) { // default home redirect response.Redirect("/" + baseUrl.TrimEnd('/') + "/index.html"); //TODO: find a solution for HG homepage redirect ---> ?" + new TimeSpan(DateTime.UtcNow.Ticks).TotalMilliseconds + "#page_control"); response.Close(); } else { var connectionWatch = Stopwatch.StartNew(); MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1} [OPEN]", response.StatusCode, request.RawUrl))); // this url is reserved for Server Sent Event stream if (url.TrimEnd('/').Equals("events")) { // TODO: move all of this to a separate function // Server sent events // NOTE: no PreProcess or PostProcess events are fired in this case //response.KeepAlive = true; response.ContentEncoding = Encoding.UTF8; response.ContentType = "text/event-stream"; response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set("Access-Control-Allow-Origin", "*"); // 2K padding for IE var padding = ":" + new String(' ', 2048) + "\n"; byte[] paddingData = System.Text.Encoding.UTF8.GetBytes(padding); response.OutputStream.Write(paddingData, 0, paddingData.Length); byte[] retryData = System.Text.Encoding.UTF8.GetBytes("retry: 1000\n"); response.OutputStream.Write(retryData, 0, retryData.Length); DateTime lastTimeStamp = DateTime.UtcNow; var lastId = context.Request.Headers.Get("Last-Event-ID"); if (lastId == null || lastId == "") { var queryValues = HttpUtility.ParseQueryString(context.Request.Url.Query); lastId = queryValues.Get("lastEventId"); } if (lastId != null && lastId != "") { double unixTimestamp = 0; double.TryParse(lastId, NumberStyles.Float | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out unixTimestamp); if (unixTimestamp != 0) { lastTimeStamp = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc); lastTimeStamp.AddSeconds(Math.Round(unixTimestamp / 1000d)); } } bool connected = true; var timeoutWatch = Stopwatch.StartNew(); while (connected) { // dirty work around for signaling new event and // avoiding locks on long socket timetout lock (sseEventToken) Monitor.Wait(sseEventToken, 1000); // safely dequeue events List<SseEvent> bufferedData; do { bufferedData = sseEventBuffer.FindAll(le => le != null && le.Timestamp.Ticks > lastTimeStamp.Ticks); if (bufferedData.Count > 0) { foreach (SseEvent entry in bufferedData) { // send events try { // The following throws an error on some mono-arm (Input string was not in the correct format) // entry.Event.UnixTimestamp.ToString("R", CultureInfo.InvariantCulture) byte[] data = System.Text.Encoding.UTF8.GetBytes("id: " + entry.Event.UnixTimestamp.ToString().Replace(",", ".") + "\ndata: " + MigService.JsonSerialize(entry.Event) + "\n\n"); response.OutputStream.Write(data, 0, data.Length); //response.OutputStream.Flush(); lastTimeStamp = entry.Timestamp; } catch (Exception e) { MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1} [ERROR: {2}]", response.StatusCode, request.RawUrl, e.Message))); connected = false; break; } } Thread.Sleep(100); } // there might be new data after sending } while (connected && bufferedData.Count > 0); // check if the remote end point is still alive every 15 seconds or so if (timeoutWatch.Elapsed.TotalSeconds > 15) { connected = connected && IsRemoteEndPointConnected(request.RemoteEndPoint); timeoutWatch.Stop(); timeoutWatch = Stopwatch.StartNew(); } } } else { try { MigClientRequest migRequest = null; if (url.StartsWith("api/")) { string message = url.Substring(url.IndexOf('/', 1) + 1); var migContext = new MigContext(ContextSource.WebServiceGateway, context); migRequest = new MigClientRequest(migContext, new MigInterfaceCommand(message)); // Disable HTTP caching response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); // Store POST data (if any) in the migRequest.RequestData field migRequest.RequestData = WebServiceUtility.ReadToEnd(request.InputStream); migRequest.RequestText = request.ContentEncoding.GetString(migRequest.RequestData); } OnPreProcessRequest(migRequest); bool requestHandled = (migRequest != null && migRequest.Handled); if (requestHandled) { SendResponseObject(context, migRequest.ResponseData); } else if (url.StartsWith(baseUrl) || baseUrl.Equals("/")) { // If request begins <base_url>, process as standard Web request string requestedFile = GetWebFilePath(url); if (!System.IO.File.Exists(requestedFile)) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, "<h1>404 - Not Found</h1>"); } else { bool isText = false; if (url.ToLower().EndsWith(".js")) // || requestedurl.EndsWith(".json")) { response.ContentType = "text/javascript"; isText = true; } else if (url.ToLower().EndsWith(".css")) { response.ContentType = "text/css"; isText = true; } else if (url.ToLower().EndsWith(".zip")) { response.ContentType = "application/zip"; } else if (url.ToLower().EndsWith(".png")) { response.ContentType = "image/png"; } else if (url.ToLower().EndsWith(".jpg")) { response.ContentType = "image/jpeg"; } else if (url.ToLower().EndsWith(".gif")) { response.ContentType = "image/gif"; } else if (url.ToLower().EndsWith(".mp3")) { response.ContentType = "audio/mp3"; } else if (url.ToLower().EndsWith(".appcache")) { response.ContentType = "text/cache-manifest"; } else { response.ContentType = "text/html"; isText = true; } var file = new System.IO.FileInfo(requestedFile); response.ContentLength64 = file.Length; bool modified = true; if (request.Headers.AllKeys.Contains("If-Modified-Since")) { var modifiedSince = DateTime.MinValue; DateTime.TryParse(request.Headers["If-Modified-Since"], out modifiedSince); if (file.LastWriteTime.ToUniversalTime().Equals(modifiedSince)) modified = false; } bool disableCacheControl = HttpCacheIgnoreCheck(url); if (!modified && !disableCacheControl) { // TODO: !IMPORTANT! exclude from caching files that contains SSI tags! response.StatusCode = (int)HttpStatusCode.NotModified; response.Headers.Set(HttpResponseHeader.Date, file.LastWriteTimeUtc.ToString().Replace(",", ".")); } else { response.Headers.Set(HttpResponseHeader.LastModified, file.LastWriteTimeUtc.ToString().Replace(",", ".")); if (disableCacheControl) { response.Headers.Set(HttpResponseHeader.CacheControl, "no-cache, no-store, must-revalidate"); response.Headers.Set(HttpResponseHeader.Pragma, "no-cache"); response.Headers.Set(HttpResponseHeader.Expires, "0"); } else { response.Headers.Set(HttpResponseHeader.CacheControl, "max-age=86400"); } // PRE PROCESS text output if (isText) { try { WebFile webFile = GetWebFile(requestedFile); response.ContentEncoding = webFile.Encoding; response.ContentType += "; charset=" + webFile.Encoding.BodyName; // We don't need to parse the content again if it's coming from the cache if (!webFile.IsCached) { string body = webFile.Content; if (requestedFile.EndsWith(".md")) { // Built-in Markdown files support body = CommonMark.CommonMarkConverter.Convert(body); // TODO: add a way to include HTML header and footer template to be appended to the // TODO: translated markdown text } else { // HTML file // replace prepocessor directives with values bool tagFound; do { tagFound = false; int ts = body.IndexOf("{include "); if (ts >= 0) { int te = body.IndexOf("}", ts); if (te > ts) { string rs = body.Substring(ts + (te - ts) + 1); string cs = body.Substring(ts, te - ts + 1); string ls = body.Substring(0, ts); // try { if (cs.StartsWith("{include ")) { string fileName = cs.Substring(9).TrimEnd('}').Trim(); fileName = GetWebFilePath(fileName); // Encoding fileEncoding = DetectWebFileEncoding(fileName); if (fileEncoding == null) fileEncoding = defaultWebFileEncoding; var incFile = System.IO.File.ReadAllText(fileName, fileEncoding) + rs; body = ls + incFile; } } catch { body = ls + "<h5 style=\"color:red\">Error processing '" + cs.Replace("{", "[").Replace("}", "]") + "'</h5>" + rs; } tagFound = true; } } } while (tagFound); // continue if a pre processor tag was found // {hostos} body = body.Replace("{hostos}", Environment.OSVersion.Platform.ToString()); // {filebase} body = body.Replace("{filebase}", Path.GetFileNameWithoutExtension(requestedFile)); } // update the cache content with parsing results webFile.Content = body; } // Store the cache item if the file cache is enabled if (enableFileCache) { UpdateWebFileCache(requestedFile, webFile.Content, response.ContentEncoding); } // WebServiceUtility.WriteStringToContext(context, webFile.Content); } catch (Exception ex) { // TODO: report internal mig interface error response.StatusCode = (int)HttpStatusCode.InternalServerError; WebServiceUtility.WriteStringToContext(context, ex.Message + "\n" + ex.StackTrace); MigService.Log.Error(ex); } } else { WebServiceUtility.WriteBytesToContext(context, System.IO.File.ReadAllBytes(requestedFile)); } } } requestHandled = true; } OnPostProcessRequest(migRequest); if (!requestHandled && migRequest != null && migRequest.Handled) { SendResponseObject(context, migRequest.ResponseData); } else if (!requestHandled) { response.StatusCode = (int)HttpStatusCode.NotFound; WebServiceUtility.WriteStringToContext(context, "<h1>404 - Not Found</h1>"); } } catch (Exception eh) { // TODO: add error logging Console.Error.WriteLine(eh); } } connectionWatch.Stop(); logExtras = " [CLOSED AFTER " + Math.Round(connectionWatch.Elapsed.TotalSeconds, 3) + " seconds]"; } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; // this will only work in Linux (mono) //response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); // this works both on Linux and Windows response.AddHeader("WWW-Authenticate", "Basic"); } } else { response.StatusCode = (int)HttpStatusCode.Unauthorized; // this will only work in Linux (mono) //response.Headers.Set(HttpResponseHeader.WwwAuthenticate, "Basic"); // this works both on Linux and Windows response.AddHeader("WWW-Authenticate", "Basic"); } MigService.Log.Info(new MigEvent(this.GetName(), remoteAddress, "HTTP", request.HttpMethod.ToString(), String.Format("{0} {1}{2}", response.StatusCode, request.RawUrl, logExtras))); } catch (Exception ex) { MigService.Log.Error(ex); } finally { // // CleanUp/Dispose allocated resources // try { request.InputStream.Close(); } catch { // TODO: add logging } try { response.OutputStream.Close(); } catch { // TODO: add logging } try { response.Close(); } catch { // TODO: add logging } try { response.Abort(); } catch { // TODO: add logging } } }
public void ProcessRequest(MigClientRequest request) { var migCommand = request.Command; string streamContent = ""; ProgramBlock currentProgram; ProgramBlock newProgram; string sketchFile = "", sketchFolder = ""; // request.ResponseData = new ResponseStatus(Status.Ok); if (homegenie.ExecuteAutomationRequest(migCommand)) { // TODO: should it just return if the request has been already processed? } if (migCommand.Command.StartsWith("Macro.")) { switch (migCommand.Command) { case "Macro.Record": homegenie.ProgramManager.MacroRecorder.RecordingEnable(); break; case "Macro.Save": newProgram = homegenie.ProgramManager.MacroRecorder.SaveMacro(migCommand.GetOption(1)); request.ResponseData = newProgram.Address.ToString(); break; case "Macro.Discard": homegenie.ProgramManager.MacroRecorder.RecordingDisable(); break; case "Macro.SetDelay": switch (migCommand.GetOption(0).ToLower()) { case "none": homegenie.ProgramManager.MacroRecorder.DelayType = MacroDelayType.None; break; case "mimic": homegenie.ProgramManager.MacroRecorder.DelayType = MacroDelayType.Mimic; break; case "fixed": double secs = double.Parse( migCommand.GetOption(1), System.Globalization.CultureInfo.InvariantCulture ); homegenie.ProgramManager.MacroRecorder.DelayType = MacroDelayType.Fixed; homegenie.ProgramManager.MacroRecorder.DelaySeconds = secs; break; default: request.ResponseData = new ResponseStatus(Status.Error); break; } break; case "Macro.GetDelay": request.ResponseData = "{ \"DelayType\" : \"" + homegenie.ProgramManager.MacroRecorder.DelayType + "\", \"DelayOptions\" : \"" + homegenie.ProgramManager.MacroRecorder.DelaySeconds + "\" }"; break; default: request.ResponseData = new ResponseStatus(Status.Error); break; } } else if (migCommand.Command.StartsWith("Scheduling.")) { switch (migCommand.Command) { case "Scheduling.Add": case "Scheduling.Update": var newSchedule = JsonConvert.DeserializeObject <SchedulerItem>(request.RequestText); var item = homegenie.ProgramManager.SchedulerService.AddOrUpdate( newSchedule.Name, newSchedule.CronExpression, newSchedule.Data, newSchedule.Description, newSchedule.Script ); if (newSchedule.BoundDevices != null) { item.BoundDevices = newSchedule.BoundDevices; } if (newSchedule.BoundModules != null) { item.BoundModules = newSchedule.BoundModules; } homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.ModuleUpdate": var mod = homegenie.Modules.Find((m) => m.Domain == migCommand.GetOption(0) && m.Address == migCommand.GetOption(1)); if (mod == null) { break; } var scheduling = JsonConvert.DeserializeObject <dynamic>(request.RequestText); for (int i = 0; i < scheduling.include.Count; i++) { string name = scheduling.include[i].Value.ToString(); var schedulerItem = homegenie.ProgramManager.SchedulerService.Get(name); if (schedulerItem != null) { schedulerItem.BoundModules.RemoveAll((mr) => mr.Domain == mod.Domain && mr.Address == mod.Address); schedulerItem.BoundModules.Add(new ModuleReference() { Domain = mod.Domain, Address = mod.Address }); } } for (int i = 0; i < scheduling.exclude.Count; i++) { string name = scheduling.exclude[i].Value.ToString(); var schedulerItem = homegenie.ProgramManager.SchedulerService.Get(name); if (schedulerItem != null) { schedulerItem.BoundModules.RemoveAll((mr) => mr.Domain == mod.Domain && mr.Address == mod.Address); } } homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Get": request.ResponseData = homegenie.ProgramManager.SchedulerService.Get(migCommand.GetOption(0)); break; case "Scheduling.Enable": homegenie.ProgramManager.SchedulerService.Enable(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Disable": homegenie.ProgramManager.SchedulerService.Disable(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Delete": homegenie.ProgramManager.SchedulerService.Remove(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.ListOccurrences": int hours = 24; int.TryParse(migCommand.GetOption(0), out hours); DateTime dateStart = DateTime.Today.ToUniversalTime(); string startFrom = migCommand.GetOption(1); if (!String.IsNullOrWhiteSpace(startFrom)) { dateStart = Utility.JavascriptToDate(long.Parse(startFrom)); } string cronExpression = migCommand.GetOption(2); List <dynamic> nextList = new List <dynamic>(); if (!String.IsNullOrEmpty(cronExpression)) { var evt = new { CronExpression = cronExpression, Occurrences = new List <double>() }; var d = dateStart; var dateEnd = dateStart.AddHours(hours); var occurs = homegenie.ProgramManager.SchedulerService.GetScheduling(dateStart, dateEnd, cronExpression); occurs.Sort(); foreach (var dt in occurs) { evt.Occurrences.Add(Utility.DateToJavascript(dt.ToUniversalTime())); } if (evt.Occurrences.Count > 0) { nextList.Add(evt); } } else { for (int s = 0; s < homegenie.ProgramManager.SchedulerService.Items.Count; s++) { var ce = homegenie.ProgramManager.SchedulerService.Items[s]; if (!ce.IsEnabled) { continue; } var evt = new { ce.Name, ce.Description, RunScript = !String.IsNullOrWhiteSpace(ce.Script), Occurrences = new List <double>() }; var d = dateStart; var dateEnd = dateStart.AddHours(hours); var occurs = homegenie.ProgramManager.SchedulerService.GetScheduling(dateStart, dateEnd, ce.CronExpression); occurs.Sort(); foreach (var dt in occurs) { evt.Occurrences.Add(Utility.DateToJavascript(dt.ToUniversalTime())); } if (evt.Occurrences.Count > 0) { nextList.Add(evt); } } } request.ResponseData = nextList; break; case "Scheduling.List": homegenie.ProgramManager.SchedulerService .Items.Sort((s1, s2) => String.Compare(s1.Name, s2.Name, StringComparison.Ordinal)); request.ResponseData = homegenie.ProgramManager.SchedulerService.Items; break; case "Scheduling.Describe": var cronDescription = ""; try { cronDescription = ExpressionDescriptor.GetDescription(migCommand.GetOption(0).Trim()); cronDescription = Char.ToLowerInvariant(cronDescription[0]) + cronDescription.Substring(1); } catch { } request.ResponseData = new ResponseText(cronDescription); break; case "Scheduling.SolarTimes": var solarTimes = new SolarTimes(DateTime.Now, homegenie.ProgramManager.SchedulerService.Location["latitude"].Value, homegenie.ProgramManager.SchedulerService.Location["longitude"].Value); request.ResponseData = solarTimes; break; default: request.ResponseData = new ResponseStatus(Status.Error); break; } } else if (migCommand.Command.StartsWith("Programs.")) { if (migCommand.Command != "Programs.Import") { streamContent = request.RequestText; } // switch (migCommand.Command) { case "Programs.Import": string archiveName = "homegenie_program_import.hgx"; if (File.Exists(archiveName)) { File.Delete(archiveName); } MIG.Gateways.WebServiceUtility .SaveFile(request.RequestData, archiveName); int newPid = homegenie.ProgramManager.GeneratePid(); newProgram = homegenie.PackageManager.ProgramImport(newPid, archiveName, migCommand.GetOption(0)); homegenie.UpdateProgramsDatabase(); request.ResponseData = new ResponseText(newProgram.Address.ToString()); break; case "Programs.Export": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); string filename = currentProgram.Address + "-" + currentProgram.Name.Replace(" ", "_"); // var writerSettings = new System.Xml.XmlWriterSettings(); writerSettings.Indent = true; writerSettings.Encoding = Encoding.UTF8; var programSerializer = new XmlSerializer(typeof(ProgramBlock)); var builder = new StringBuilder(); var writer = System.Xml.XmlWriter.Create(builder, writerSettings); programSerializer.Serialize(writer, currentProgram); writer.Close(); // (request.Context.Data as HttpListenerContext).Response.AddHeader( "Content-Type", "application/octet-stream; charset=utf-8" ); // if (currentProgram.Type.ToLower() == "arduino") { string arduinoBundle = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Utility.GetTmpFolder(), "export", filename + ".zip"); if (File.Exists(arduinoBundle)) { File.Delete(arduinoBundle); } else if (!Directory.Exists(Path.GetDirectoryName(arduinoBundle))) { Directory.CreateDirectory(Path.GetDirectoryName(arduinoBundle)); } string mainProgramFile = Path.Combine(Path.GetDirectoryName(arduinoBundle), "program.hgx"); File.WriteAllText( mainProgramFile, builder.ToString() ); Utility.AddFileToZip(arduinoBundle, mainProgramFile, "program.hgx"); sketchFolder = Path.Combine("programs", "arduino", currentProgram.Address.ToString()); foreach (string f in Directory.GetFiles(sketchFolder)) { if (!Path.GetFileName(f).StartsWith("sketch_")) { Utility.AddFileToZip( arduinoBundle, Path.Combine(sketchFolder, Path.GetFileName(f)), Path.Combine( "src", Path.GetFileName(f) ) ); } } // byte[] bundleData = File.ReadAllBytes(arduinoBundle); (request.Context.Data as HttpListenerContext).Response.AddHeader( "Content-Disposition", "attachment; filename=\"" + filename + ".zip\"" ); (request.Context.Data as HttpListenerContext).Response.OutputStream.Write(bundleData, 0, bundleData.Length); } else { (request.Context.Data as HttpListenerContext).Response.AddHeader( "Content-Disposition", "attachment; filename=\"" + filename + ".hgx\"" ); request.ResponseData = builder.ToString(); } break; case "Programs.List": var programList = new List <ProgramBlock>(homegenie.ProgramManager.Programs); programList.Sort(delegate(ProgramBlock p1, ProgramBlock p2) { string c1 = p1.Name + " " + p1.Address; string c2 = p2.Name + " " + p2.Address; return(c1.CompareTo(c2)); }); request.ResponseData = programList; break; case "Programs.Get": try { var prg = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); var settings = new JsonSerializerSettings { Formatting = Formatting.Indented }; request.ResponseData = JsonConvert.SerializeObject(prg, settings); } catch (Exception ex) { request.ResponseData = new ResponseText("ERROR: \n" + ex.Message + "\n\n" + ex.StackTrace); } break; case "Programs.Add": try { // This works with HG > 1.4.x newProgram = JsonConvert.DeserializeObject <ProgramBlock>(streamContent); } catch (Exception e) { // this is for backward compatibility with HG v1.3.x newProgram = new ProgramBlock() { Group = migCommand.GetOption(0), Name = streamContent, Type = "CSharp" }; } newProgram.Address = homegenie.ProgramManager.GeneratePid(); homegenie.ProgramManager.ProgramAdd(newProgram); homegenie.UpdateProgramsDatabase(); request.ResponseData = new ResponseText(newProgram.Address.ToString()); break; case "Programs.Clone": var copy = homegenie.ProgramManager .ProgramClone(int.Parse(migCommand.GetOption(0)), migCommand.GetOption(1)); homegenie.UpdateProgramsDatabase(); request.ResponseData = new ResponseText(copy.Address.ToString()); break; case "Programs.Delete": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { // TODO: remove groups associations as well homegenie.ProgramManager.ProgramRemove(currentProgram); homegenie.UpdateProgramsDatabase(); // remove associated module entry homegenie.Modules.RemoveAll(m => m.Domain == Domains.HomeAutomation_HomeGenie_Automation && m.Address == currentProgram.Address.ToString()); homegenie.UpdateModulesDatabase(); } break; case "Programs.Compile": case "Programs.Update": newProgram = JsonConvert.DeserializeObject <ProgramBlock>(streamContent); currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == newProgram.Address); // if (currentProgram == null) { newProgram.Address = homegenie.ProgramManager.GeneratePid(); homegenie.ProgramManager.ProgramAdd(newProgram); currentProgram = newProgram; } else { bool typeChanged = !string.Equals(currentProgram.Type, newProgram.Type, StringComparison.CurrentCultureIgnoreCase); currentProgram.Type = newProgram.Type; currentProgram.Group = newProgram.Group; currentProgram.Name = newProgram.Name; currentProgram.Description = newProgram.Description; currentProgram.AutoRestartEnabled = newProgram.AutoRestartEnabled; currentProgram.Cloneable = newProgram.Cloneable; if (typeChanged) { currentProgram.Engine.SetHost(homegenie); } currentProgram.IsEnabled = newProgram.IsEnabled; currentProgram.ScriptSetup = newProgram.ScriptSetup; currentProgram.ScriptSource = newProgram.ScriptSource; } // if (migCommand.Command == "Programs.Compile") { // reset previous error status currentProgram.IsEnabled = false; currentProgram.Engine.StopProgram(); currentProgram.ScriptErrors = ""; homegenie.ProgramManager.RaiseProgramModuleEvent( currentProgram, Properties.RuntimeError, "" ); // List <ProgramError> errors = homegenie.ProgramManager .ProgramCompile(currentProgram); currentProgram.IsEnabled = newProgram.IsEnabled && errors.Count == 0; currentProgram.ScriptErrors = JsonConvert.SerializeObject(errors); request.ResponseData = currentProgram.ScriptErrors; } else { request.ResponseData = new ResponseStatus(Status.Ok); } homegenie.UpdateProgramsDatabase(); // homegenie.modules_RefreshPrograms(); homegenie.modules_RefreshVirtualModules(); //homegenie.modules_Sort(); break; case "Programs.Arduino.FileLoad": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); sketchFile = migCommand.GetOption(1); if (sketchFile == "main") { // "main" is a special keyword to indicate the main program sketch file sketchFile = ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0)); } sketchFile = Path.Combine(sketchFolder, Path.GetFileName(sketchFile)); request.ResponseData = new ResponseText(File.ReadAllText(sketchFile)); break; case "Programs.Arduino.FileSave": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); sketchFile = Path.Combine(sketchFolder, Path.GetFileName(migCommand.GetOption(1))); File.WriteAllText(sketchFile, streamContent); break; case "Programs.Arduino.FileAdd": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); if (!Directory.Exists(sketchFolder)) { Directory.CreateDirectory(sketchFolder); } sketchFile = Path.Combine(sketchFolder, Path.GetFileName(migCommand.GetOption(1))); if (File.Exists(sketchFile)) { request.ResponseData = new ResponseText("EXISTS"); } else if (!ArduinoAppFactory.IsValidProjectFile(sketchFile)) { request.ResponseData = new ResponseText("INVALID_NAME"); } else { StreamWriter sw = File.CreateText(sketchFile); sw.Close(); sw.Dispose(); sw = null; request.ResponseData = new ResponseText("OK"); } break; case "Programs.Arduino.FileDelete": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); sketchFile = Path.Combine(sketchFolder, Path.GetFileName(migCommand.GetOption(1))); if (!File.Exists(sketchFile)) { request.ResponseData = new ResponseText("NOT_FOUND"); } else { File.Delete(sketchFile); request.ResponseData = new ResponseText("OK"); } break; case "Programs.Arduino.FileList": sketchFolder = Path.GetDirectoryName(ArduinoAppFactory.GetSketchFile(migCommand.GetOption(0))); List <string> files = new List <string>(); foreach (string f in Directory.GetFiles(sketchFolder)) { if (ArduinoAppFactory.IsValidProjectFile(f)) { files.Add(Path.GetFileName(f)); } } request.ResponseData = files; break; case "Programs.Run": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { // clear any runtime errors before running currentProgram.ScriptErrors = ""; homegenie.ProgramManager.RaiseProgramModuleEvent( currentProgram, Properties.RuntimeError, "" ); currentProgram.IsEnabled = true; System.Threading.Thread.Sleep(500); ProgramRun(migCommand.GetOption(0), migCommand.GetOption(1)); } break; case "Programs.Toggle": currentProgram = ProgramToggle(migCommand.GetOption(0), migCommand.GetOption(1)); break; case "Programs.Break": currentProgram = ProgramBreak(migCommand.GetOption(0)); break; case "Programs.Restart": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { currentProgram.IsEnabled = false; try { currentProgram.Engine.StopProgram(); } catch { } currentProgram.IsEnabled = true; homegenie.UpdateProgramsDatabase(); } break; case "Programs.Enable": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { currentProgram.IsEnabled = true; homegenie.UpdateProgramsDatabase(); } break; case "Programs.Disable": currentProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == int.Parse(migCommand.GetOption(0))); if (currentProgram != null) { currentProgram.IsEnabled = false; try { currentProgram.Engine.StopProgram(); } catch { } homegenie.UpdateProgramsDatabase(); } break; case "Programs.OptionsGet": var programModule = homegenie.Modules.Find(m => m.Domain == migCommand.GetOption(0) && m.Address == migCommand.GetOption(1)); if (programModule != null) { var options = new List <OptionField>(); var programOptions = new ModuleOptions() { id = programModule.Address, name = programModule.Name, description = programModule.Description, items = options }; programModule.Properties.ForEach((o) => { if (o.Name.StartsWith("ConfigureOptions.")) { var fieldType = o.FieldType.Split(':'); options.Add(new OptionField() { pid = programModule.Address, type = new OptionFieldType() { id = fieldType[0], options = fieldType.Skip(1).ToList <object>() }, name = o.Name, description = o.Description, field = new ModuleField() { key = o.Name, value = o.Value, timestamp = o.UpdateTime.ToString("o") } }); } }); options.Sort((o1, o2) => (o1.description).CompareTo(o2.description)); request.ResponseData = JsonConvert.SerializeObject(programOptions); } break; default: request.ResponseData = new ResponseStatus(Status.Error); break; } } else { request.ResponseData = new ResponseStatus(Status.Error); } }
private void HandleScheduling(MigInterfaceCommand migCommand, MigClientRequest request) { switch (migCommand.Command) { case "Scheduling.Add": case "Scheduling.Update": var newSchedule = JsonConvert.DeserializeObject <SchedulerItem>(request.RequestText); var item = homegenie.ProgramManager.SchedulerService.AddOrUpdate( newSchedule.Name, newSchedule.CronExpression, newSchedule.Data, newSchedule.Description, newSchedule.Script ); if (newSchedule.BoundDevices != null) { item.BoundDevices = newSchedule.BoundDevices; } if (newSchedule.BoundModules != null) { item.BoundModules = newSchedule.BoundModules; } homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Delete": homegenie.ProgramManager.SchedulerService.Remove(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Enable": homegenie.ProgramManager.SchedulerService.Enable(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Disable": homegenie.ProgramManager.SchedulerService.Disable(migCommand.GetOption(0)); homegenie.UpdateSchedulerDatabase(); break; case "Scheduling.Get": request.ResponseData = homegenie.ProgramManager.SchedulerService.Get(migCommand.GetOption(0)); break; case "Scheduling.ListOccurrences": var hours = 24; int.TryParse(migCommand.GetOption(0), out hours); var dateStart = DateTime.Today.ToUniversalTime(); var startFrom = migCommand.GetOption(1); if (!string.IsNullOrWhiteSpace(startFrom)) { dateStart = Utility.JavascriptToDate(long.Parse(startFrom)); } var nextList = new List <dynamic>(); foreach (var schedulerItem in homegenie.ProgramManager.SchedulerService.Items) { if (!schedulerItem.IsEnabled) { continue; } var evt = new { Name = schedulerItem.Name, Description = schedulerItem.Description, RunScript = !string.IsNullOrWhiteSpace(schedulerItem.Script), Occurrences = new List <double>() }; var dateEnd = dateStart.AddHours(hours); var occurs = homegenie.ProgramManager.SchedulerService.GetScheduling( dateStart, dateEnd, schedulerItem.CronExpression); occurs.Sort(); foreach (var dt in occurs) { evt.Occurrences.Add(Utility.DateToJavascript(dt.ToUniversalTime())); } if (evt.Occurrences.Count > 0) { nextList.Add(evt); } } request.ResponseData = nextList; break; case "Scheduling.List": homegenie.ProgramManager.SchedulerService.Items.Sort((s1, s2) => s1.Name.CompareTo(s2.Name)); request.ResponseData = homegenie.ProgramManager.SchedulerService.Items; break; case "Scheduling.Describe": var cronDescription = ""; try { cronDescription = ExpressionDescriptor.GetDescription(migCommand.GetOption(0).Trim()); cronDescription = char.ToLowerInvariant(cronDescription[0]) + cronDescription.Substring(1); } catch { } request.ResponseData = new ResponseText(cronDescription); break; case "Scheduling.SolarTimes": var solarTimes = new SolarTimes(DateTime.Now, homegenie.ProgramManager.SchedulerService.Location["latitude"].Value, homegenie.ProgramManager.SchedulerService.Location["longitude"].Value); request.ResponseData = solarTimes; break; } }
public void ProcessRequest(MigClientRequest request) { var migCommand = request.Command; string response; var domain = ""; var address = ""; DateTime dateStart; var deviceAddress = migCommand.GetOption(0).Split(':'); if (deviceAddress.Length == 2) { domain = deviceAddress[0]; address = deviceAddress[1]; } switch (migCommand.Command) { case "Global.CounterTotal": var counter = _homegenie.Statistics.GetTotalCounter(migCommand.GetOption(0), 3600); request.ResponseData = new ResponseText(counter.ToString("0.000", System.Globalization.CultureInfo.InvariantCulture)); break; case "Global.TimeRange": // TODO create dedicated class or use Tuple<DateTime, DateTime> var dateRange = _homegenie.Statistics.GetDateRange(); request.ResponseData = JsonConvert.SerializeObject(new { StartTime = Utility.DateToJavascript(dateRange.start), EndTime = Utility.DateToJavascript(dateRange.end), }); break; case "Database.Reset": _homegenie.Statistics.ResetDatabase(); break; case "Configuration.Get": // Just one at the moment. request.ResponseData = JsonConvert.SerializeObject(new { StatisticsUIRefreshSeconds = _homegenie.SystemConfiguration.HomeGenie.Statistics.StatisticsUIRefreshSeconds }); break; case "Parameter.List": if (deviceAddress.Length == 2) { domain = deviceAddress[0]; address = deviceAddress[1]; } var statParameters = _homegenie.Statistics.GetParametersList(domain, address); response = JsonConvert.SerializeObject(statParameters); request.ResponseData = response; break; case "Parameter.Counter": if (deviceAddress.Length == 2) { domain = deviceAddress[0]; address = deviceAddress[1]; } dateStart = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(2))); var dateEnd = Utility.JavascriptToDate(long.Parse(migCommand.GetOption(3))); var hoursAverage = _homegenie.Statistics.GetHourlyCounter(domain, address, migCommand.GetOption(0), 3600, dateStart, dateEnd); response = JsonConvert.SerializeObject(hoursAverage); request.ResponseData = response; break; // [hourly MIN, hourly MAX, hourly AVG, today's SUM values for Meters or AVG values for everything else] case "Parameter.StatsHour": var hourlyStats = GetHourlyStats(migCommand); response = JsonConvert.SerializeObject(hourlyStats); request.ResponseData = response; break; // [detailed stats through days] // TODO rename this method to smth like GetDetailedStats case "Parameter.StatsDay": var dailyStats = GetDailyStats(migCommand); response = JsonConvert.SerializeObject(dailyStats); request.ResponseData = response; break; // [ [[stats], [moduleName]], [[stats], [moduleName]] ...] case "Parameter.StatsMultiple": var multipleModulesStats = GetMultipleModulesStats(migCommand); response = JsonConvert.SerializeObject(multipleModulesStats); request.ResponseData = response; break; case "Parameter.StatDelete": var dateText = migCommand.GetOption(0).Replace('.', ','); dateStart = Utility.JavascriptToDateUtc(double.Parse(dateText)); var responseDelete = _homegenie.Statistics.DeleteStat(dateStart, migCommand.GetOption(1)); request.ResponseData = responseDelete; break; } }