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