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