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