Utilities/HttpServer.cs
author sl
Sun, 03 Feb 2013 19:06:01 +0100
changeset 392 8af90fa0940f
parent 386 7094d5dd924b
permissions -rw-r--r--
Now fetching some of our Sound Graph DLL function pointers.
     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 }