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