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