Utilities/HttpServer.cs
author moel.mich
Sat, 03 Aug 2013 13:12:07 +0000
changeset 418 3bba187d41c2
parent 387 87093432c843
permissions -rw-r--r--
Changed the Intel core temperature reading to evaluate the "Reading Valid" bit 31 for package level sensors as well (undocumented).
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7 	Copyright (C) 2012 Prince Samuel <prince.samuel@gmail.com>
     8   Copyright (C) 2012-2013 Michael Möller <mmoeller@openhardwaremonitor.org>
     9 
    10 */
    11 
    12 using System;
    13 using System.Drawing;
    14 using System.Drawing.Imaging;
    15 using System.IO;
    16 using System.Net;
    17 using System.Reflection;
    18 using System.Text;
    19 using System.Threading;
    20 using OpenHardwareMonitor.GUI;
    21 using OpenHardwareMonitor.Hardware;
    22 
    23 namespace OpenHardwareMonitor.Utilities {
    24 
    25   public class HttpServer {
    26     private HttpListener listener;
    27     private int listenerPort, nodeCount;
    28     private Thread listenerThread;
    29     private Node root;
    30 
    31     public HttpServer(Node node, int port) {
    32       root = node;
    33       listenerPort = port;
    34 
    35       //JSON node count. 
    36       nodeCount = 0;
    37 
    38       try {
    39         listener = new HttpListener();
    40         listener.IgnoreWriteExceptions = true;
    41       } catch (PlatformNotSupportedException) {
    42         listener = null;
    43       }
    44     }
    45 
    46     public bool PlatformNotSupported {
    47       get {
    48         return listener == null;
    49       }
    50     }
    51 
    52     public Boolean StartHTTPListener() {
    53       if (PlatformNotSupported)
    54         return false;
    55 
    56       try {
    57         if (listener.IsListening)
    58           return true;
    59 
    60         string prefix = "http://+:" + listenerPort + "/";
    61         listener.Prefixes.Clear();
    62         listener.Prefixes.Add(prefix);
    63         listener.Start();
    64 
    65         if (listenerThread == null) {
    66           listenerThread = new Thread(HandleRequests);
    67           listenerThread.Start();
    68         }
    69       } catch (Exception) {
    70         return false;
    71       }
    72 
    73       return true;
    74     }
    75 
    76     public Boolean StopHTTPListener() {
    77       if (PlatformNotSupported)
    78         return false;
    79 
    80       try {
    81         listenerThread.Abort();
    82         listener.Stop();
    83         listenerThread = null;
    84       } catch (HttpListenerException) {
    85       } catch (ThreadAbortException) {
    86       } catch (NullReferenceException) {
    87       } catch (Exception) {
    88       }
    89       return true;
    90     }
    91 
    92     private void HandleRequests() {
    93 
    94       while (listener.IsListening) {
    95         var context = listener.BeginGetContext(
    96           new AsyncCallback(ListenerCallback), listener);
    97         context.AsyncWaitHandle.WaitOne();
    98       }
    99     }
   100 
   101     private void ListenerCallback(IAsyncResult result) {
   102       HttpListener listener = (HttpListener)result.AsyncState;
   103       if (listener == null || !listener.IsListening)
   104         return;
   105 
   106       // Call EndGetContext to complete the asynchronous operation.
   107       HttpListenerContext context;
   108       try {
   109         context = listener.EndGetContext(result);     
   110       } catch (Exception) {
   111         return;
   112       }
   113 
   114       HttpListenerRequest request = context.Request;
   115 
   116       var requestedFile = request.RawUrl.Substring(1);
   117       if (requestedFile == "data.json") {
   118         SendJSON(context.Response);
   119         return;
   120       }
   121 
   122       if (requestedFile.Contains("images_icon")) {
   123         ServeResourceImage(context.Response, 
   124           requestedFile.Replace("images_icon/", ""));
   125         return;
   126       }
   127 
   128       // default file to be served
   129       if (string.IsNullOrEmpty(requestedFile))
   130         requestedFile = "index.html";
   131 
   132       string[] splits = requestedFile.Split('.');
   133       string ext = splits[splits.Length - 1];
   134       ServeResourceFile(context.Response, 
   135         "Web." + requestedFile.Replace('/', '.'), ext);
   136     }
   137 
   138     private void ServeResourceFile(HttpListenerResponse response, string name, 
   139       string ext) 
   140     {
   141       // resource names do not support the hyphen
   142       name = "OpenHardwareMonitor.Resources." + 
   143         name.Replace("custom-theme", "custom_theme");
   144 
   145       string[] names =
   146         Assembly.GetExecutingAssembly().GetManifestResourceNames();
   147       for (int i = 0; i < names.Length; i++) {
   148         if (names[i].Replace('\\', '.') == name) {
   149           using (Stream stream = Assembly.GetExecutingAssembly().
   150             GetManifestResourceStream(names[i])) {
   151             response.ContentType = GetcontentType("." + ext);
   152             response.ContentLength64 = stream.Length;
   153             byte[] buffer = new byte[512 * 1024];
   154             int len;
   155             try {
   156               Stream output = response.OutputStream;
   157               while ((len = stream.Read(buffer, 0, buffer.Length)) > 0) {
   158                 output.Write(buffer, 0, len);
   159               }
   160               output.Flush();
   161               output.Close();              
   162               response.Close();
   163             } catch (HttpListenerException) { 
   164             } catch (InvalidOperationException) { 
   165             }
   166             return;
   167           }          
   168         }
   169       }
   170 
   171       response.StatusCode = 404;
   172       response.Close();
   173     }
   174 
   175     private void ServeResourceImage(HttpListenerResponse response, string name) {
   176       name = "OpenHardwareMonitor.Resources." + name;
   177 
   178       string[] names =
   179         Assembly.GetExecutingAssembly().GetManifestResourceNames();
   180       for (int i = 0; i < names.Length; i++) {
   181         if (names[i].Replace('\\', '.') == name) {
   182           using (Stream stream = Assembly.GetExecutingAssembly().
   183             GetManifestResourceStream(names[i])) {
   184 
   185             Image image = Image.FromStream(stream);
   186             response.ContentType = "image/png";
   187             try {
   188               Stream output = response.OutputStream;
   189               using (MemoryStream ms = new MemoryStream()) {
   190                 image.Save(ms, ImageFormat.Png);
   191                 ms.WriteTo(output);
   192               }
   193               output.Close();
   194             } catch (HttpListenerException) {              
   195             }
   196             image.Dispose();
   197             response.Close();
   198             return;
   199           }
   200         }
   201       }
   202 
   203       response.StatusCode = 404;
   204       response.Close();
   205     }
   206 
   207     private void SendJSON(HttpListenerResponse response) {
   208 
   209       string JSON = "{\"id\": 0, \"Text\": \"Sensor\", \"Children\": [";
   210       nodeCount = 1;
   211       JSON += GenerateJSON(root);
   212       JSON += "]";
   213       JSON += ", \"Min\": \"Min\"";
   214       JSON += ", \"Value\": \"Value\"";
   215       JSON += ", \"Max\": \"Max\"";
   216       JSON += ", \"ImageURL\": \"\"";
   217       JSON += "}";
   218 
   219       var responseContent = JSON;
   220       byte[] buffer = Encoding.UTF8.GetBytes(responseContent);
   221 
   222       response.AddHeader("Cache-Control", "no-cache");
   223 
   224       response.ContentLength64 = buffer.Length;
   225       response.ContentType = "application/json";
   226 
   227       try {
   228         Stream output = response.OutputStream;
   229         output.Write(buffer, 0, buffer.Length);
   230         output.Close();
   231       } catch (HttpListenerException) {
   232       }
   233 
   234       response.Close();
   235     }
   236 
   237     private string GenerateJSON(Node n) {
   238       string JSON = "{\"id\": " + nodeCount + ", \"Text\": \"" + n.Text 
   239         + "\", \"Children\": [";
   240       nodeCount++;
   241 
   242       foreach (Node child in n.Nodes)
   243         JSON += GenerateJSON(child) + ", ";
   244       if (JSON.EndsWith(", "))
   245         JSON = JSON.Remove(JSON.LastIndexOf(","));
   246       JSON += "]";
   247 
   248       if (n is SensorNode) {
   249         JSON += ", \"Min\": \"" + ((SensorNode)n).Min + "\"";
   250         JSON += ", \"Value\": \"" + ((SensorNode)n).Value + "\"";
   251         JSON += ", \"Max\": \"" + ((SensorNode)n).Max + "\"";
   252         JSON += ", \"ImageURL\": \"images/transparent.png\"";
   253       } else if (n is HardwareNode) {
   254         JSON += ", \"Min\": \"\"";
   255         JSON += ", \"Value\": \"\"";
   256         JSON += ", \"Max\": \"\"";
   257         JSON += ", \"ImageURL\": \"images_icon/" + 
   258           GetHardwareImageFile((HardwareNode)n) + "\"";
   259       } else if (n is TypeNode) {
   260         JSON += ", \"Min\": \"\"";
   261         JSON += ", \"Value\": \"\"";
   262         JSON += ", \"Max\": \"\"";
   263         JSON += ", \"ImageURL\": \"images_icon/" + 
   264           GetTypeImageFile((TypeNode)n) + "\"";
   265       } else {
   266         JSON += ", \"Min\": \"\"";
   267         JSON += ", \"Value\": \"\"";
   268         JSON += ", \"Max\": \"\"";
   269         JSON += ", \"ImageURL\": \"images_icon/computer.png\"";
   270       }
   271 
   272       JSON += "}";
   273       return JSON;
   274     }
   275 
   276     private static void ReturnFile(HttpListenerContext context, string filePath) 
   277     {
   278       context.Response.ContentType = 
   279         GetcontentType(Path.GetExtension(filePath));
   280       const int bufferSize = 1024 * 512; //512KB
   281       var buffer = new byte[bufferSize];
   282       using (var fs = File.OpenRead(filePath)) {
   283 
   284         context.Response.ContentLength64 = fs.Length;
   285         int read;
   286         while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
   287           context.Response.OutputStream.Write(buffer, 0, read);
   288       }
   289 
   290       context.Response.OutputStream.Close();
   291     }
   292 
   293     private static string GetcontentType(string extension) {
   294       switch (extension) {
   295         case ".avi": return "video/x-msvideo";
   296         case ".css": return "text/css";
   297         case ".doc": return "application/msword";
   298         case ".gif": return "image/gif";
   299         case ".htm":
   300         case ".html": return "text/html";
   301         case ".jpg":
   302         case ".jpeg": return "image/jpeg";
   303         case ".js": return "application/x-javascript";
   304         case ".mp3": return "audio/mpeg";
   305         case ".png": return "image/png";
   306         case ".pdf": return "application/pdf";
   307         case ".ppt": return "application/vnd.ms-powerpoint";
   308         case ".zip": return "application/zip";
   309         case ".txt": return "text/plain";
   310         default: return "application/octet-stream";
   311       }
   312     }
   313 
   314     private static string GetHardwareImageFile(HardwareNode hn) {
   315 
   316       switch (hn.Hardware.HardwareType) {
   317         case HardwareType.CPU:
   318           return "cpu.png";
   319         case HardwareType.GpuNvidia:
   320           return "nvidia.png";
   321         case HardwareType.GpuAti:
   322           return "ati.png";
   323         case HardwareType.HDD:
   324           return "hdd.png";
   325         case HardwareType.Heatmaster:
   326           return "bigng.png";
   327         case HardwareType.Mainboard:
   328           return "mainboard.png";
   329         case HardwareType.SuperIO:
   330           return "chip.png";
   331         case HardwareType.TBalancer:
   332           return "bigng.png";
   333         case HardwareType.RAM:
   334           return "ram.png";
   335         default:
   336           return "cpu.png";
   337       }
   338 
   339     }
   340 
   341     private static string GetTypeImageFile(TypeNode tn) {
   342 
   343       switch (tn.SensorType) {
   344         case SensorType.Voltage:
   345           return "voltage.png";
   346         case SensorType.Clock:
   347           return "clock.png";
   348         case SensorType.Load:
   349           return "load.png";
   350         case SensorType.Temperature:
   351           return "temperature.png";
   352         case SensorType.Fan:
   353           return "fan.png";
   354         case SensorType.Flow:
   355           return "flow.png";
   356         case SensorType.Control:
   357           return "control.png";
   358         case SensorType.Level:
   359           return "level.png";
   360         case SensorType.Power:
   361           return "power.png";
   362         default:
   363           return "power.png";
   364       }
   365 
   366     }
   367 
   368     public int ListenerPort {
   369       get { return listenerPort; }
   370       set { listenerPort = value; }
   371     }
   372 
   373     ~HttpServer() {
   374       if (PlatformNotSupported)
   375         return;
   376 
   377       StopHTTPListener();
   378       listener.Abort();
   379     }
   380 
   381     public void Quit() {
   382       if (PlatformNotSupported)
   383         return;
   384 
   385       StopHTTPListener();
   386       listener.Abort();
   387     }
   388   }
   389 }