Пример #1
0
 protected virtual void OnPostProcessRequest(MigClientRequest request)
 {
     if (request != null && PostProcessRequest != null)
     {
         PostProcessRequest(this, new ProcessRequestEventArgs(request));
     }
 }
Пример #2
0
        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);
            }
        }
Пример #3
0
        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;
            }
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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;
            }
        }
Пример #6
0
        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
                }
            }
        }
Пример #7
0
        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;
                }
            }
        }
Пример #8
0
 protected virtual void OnPreProcessRequest(MigClientRequest request)
 {
     if (request != null && PreProcessRequest != null)
         PreProcessRequest(this, new ProcessRequestEventArgs(request));
 }
Пример #9
0
 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
                }
            }
        }
Пример #12
0
 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
                }
            }
        }
Пример #14
0
        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);
            }
        }
Пример #15
0
        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;
            }
        }
Пример #16
0
        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;
            }
        }