moel@348: /* moel@348: moel@348: This Source Code Form is subject to the terms of the Mozilla Public moel@348: License, v. 2.0. If a copy of the MPL was not distributed with this moel@348: file, You can obtain one at http://mozilla.org/MPL/2.0/. moel@348: moel@348: Copyright (C) 2012 Prince Samuel moel@348: moel@348: */ moel@348: moel@348: using System; moel@348: using System.Collections.Generic; moel@348: using System.Text; moel@348: using System.Net; moel@348: using System.Threading; moel@348: using System.IO; moel@348: using OpenHardwareMonitor.GUI; moel@348: using OpenHardwareMonitor.Hardware; moel@348: using System.Reflection; moel@348: using System.Drawing; moel@348: using System.Drawing.Imaging; moel@348: moel@348: namespace OpenHardwareMonitor.Utilities moel@348: { moel@348: public class HttpServer moel@348: { moel@348: private HttpListener listener; moel@348: private int listenerPort, nodeCount; moel@348: private Thread listenerThread; moel@348: private Node root; moel@348: moel@348: public HttpServer(Node r, int p) moel@348: { moel@348: root = r; moel@348: listenerPort = p; moel@348: //JSON node count. moel@348: nodeCount = 0; moel@348: listener = new HttpListener(); moel@348: } moel@348: moel@348: public Boolean startHTTPListener() moel@348: { moel@348: try moel@348: { moel@348: if (listener.IsListening) moel@348: return true; moel@348: moel@348: string prefix = "http://+:" + listenerPort + "/"; moel@348: listener.Prefixes.Clear(); moel@348: listener.Prefixes.Add(prefix); moel@348: listener.Start(); moel@348: moel@348: if (listenerThread == null) moel@348: { moel@348: listenerThread = new Thread(HandleRequests); moel@348: listenerThread.Start(); moel@348: } moel@348: } moel@348: catch (Exception e) moel@348: { moel@348: return false; moel@348: } moel@348: moel@348: return true; moel@348: } moel@348: moel@348: public Boolean stopHTTPListener() moel@348: { moel@348: try moel@348: { moel@348: listenerThread.Abort(); moel@348: listener.Stop(); moel@348: listenerThread = null; moel@348: } moel@348: catch (System.Net.HttpListenerException e) moel@348: { moel@348: } moel@348: catch (System.Threading.ThreadAbortException e) moel@348: { moel@348: } moel@348: catch (System.NullReferenceException e) moel@348: { moel@348: } moel@348: catch (Exception e) moel@348: { moel@348: } moel@348: return true; moel@348: } moel@348: moel@348: public void HandleRequests() moel@348: { moel@348: moel@348: while (listener.IsListening) moel@348: { moel@348: var context = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener); moel@348: context.AsyncWaitHandle.WaitOne(); moel@348: } moel@348: } moel@348: moel@348: public void ListenerCallback(IAsyncResult result) moel@348: { moel@348: HttpListener listener = (HttpListener)result.AsyncState; moel@348: if (listener == null || !listener.IsListening) moel@348: return; moel@348: // Call EndGetContext to complete the asynchronous operation. moel@348: HttpListenerContext context = listener.EndGetContext(result); moel@348: HttpListenerRequest request = context.Request; moel@348: moel@348: var requestedFile = request.RawUrl.Substring(1); moel@348: if (requestedFile == "data.json") moel@348: { moel@348: sendJSON(context); moel@348: return; moel@348: } moel@348: moel@348: if (requestedFile.Contains("images_icon")) moel@348: { moel@348: serveResourceImage(context, requestedFile.Replace("images_icon/", "")); moel@348: return; moel@348: } moel@348: moel@348: //default file to be served moel@348: if (string.IsNullOrEmpty(requestedFile)) moel@348: requestedFile = "index.html"; moel@348: moel@348: string[] splits = requestedFile.Split('.'); moel@348: string ext = splits[splits.Length - 1]; moel@348: serveResourceFile(context, "Web." + requestedFile.Replace('/', '.'), ext); moel@348: } moel@348: moel@348: private void serveResourceFile(HttpListenerContext context ,string name, string ext) { moel@348: moel@348: //hack! resource names do not support the hyphen moel@348: name = "OpenHardwareMonitor.Resources." + name.Replace("custom-theme", "custom_theme"); moel@348: moel@348: string[] names = moel@348: Assembly.GetExecutingAssembly().GetManifestResourceNames(); moel@348: for (int i = 0; i < names.Length; i++) { moel@348: if (names[i].Replace('\\', '.') == name) { moel@348: using (Stream stream = Assembly.GetExecutingAssembly(). moel@348: GetManifestResourceStream(names[i])) { moel@348: context.Response.ContentType = getcontentType("." + ext); moel@348: context.Response.ContentLength64 = stream.Length; moel@348: byte[] buffer = new byte[512 * 1024]; moel@348: int len; moel@348: while ((len = stream.Read(buffer, 0, buffer.Length)) > 0) moel@348: { moel@348: context.Response.OutputStream.Write(buffer, 0, len); moel@348: } moel@348: context.Response.OutputStream.Close(); moel@348: } moel@348: return; moel@348: } moel@348: } moel@348: context.Response.OutputStream.Close(); moel@348: context.Response.StatusCode = 404; moel@348: context.Response.Close(); moel@348: } moel@348: moel@348: private void serveResourceImage(HttpListenerContext context ,string name) { moel@348: name = "OpenHardwareMonitor.Resources." + name; moel@348: moel@348: string[] names = moel@348: Assembly.GetExecutingAssembly().GetManifestResourceNames(); moel@348: for (int i = 0; i < names.Length; i++) { moel@348: if (names[i].Replace('\\', '.') == name) { moel@348: using (Stream stream = Assembly.GetExecutingAssembly(). moel@348: GetManifestResourceStream(names[i])) { moel@348: moel@348: Image image = Image.FromStream(stream); moel@348: context.Response.ContentType = "image/png"; moel@348: using (MemoryStream ms = new MemoryStream()) moel@348: { moel@348: image.Save(ms, ImageFormat.Png); moel@348: ms.WriteTo(context.Response.OutputStream); moel@348: } moel@348: context.Response.OutputStream.Close(); moel@348: image.Dispose(); moel@348: return; moel@348: } moel@348: } moel@348: } moel@348: context.Response.OutputStream.Close(); moel@348: context.Response.StatusCode = 404; moel@348: context.Response.Close(); moel@348: } moel@348: moel@348: private void sendJSON(HttpListenerContext context) moel@348: { moel@348: moel@348: string JSON = "{\"id\": 0, \"Text\": \"Sensor\", \"Children\": ["; moel@348: nodeCount = 1; moel@348: JSON += generateJSON(root); moel@348: JSON += "]"; moel@348: JSON += ", \"Min\": \"Min\""; moel@348: JSON += ", \"Value\": \"Value\""; moel@348: JSON += ", \"Max\": \"Max\""; moel@348: JSON += ", \"ImageURL\": \"\""; moel@348: JSON += "}"; moel@348: moel@348: var responseContent = JSON; moel@348: byte[] buffer = Encoding.UTF8.GetBytes(responseContent); moel@348: moel@348: context.Response.ContentLength64 = buffer.Length; moel@348: context.Response.ContentType = "application/json"; moel@348: moel@348: Stream outputStream = context.Response.OutputStream; moel@348: outputStream.Write(buffer, 0, buffer.Length); moel@348: outputStream.Close(); moel@348: moel@348: } moel@348: moel@348: private string generateJSON(Node n) moel@348: { moel@348: string JSON = "{\"id\": " + nodeCount + ", \"Text\": \"" + n.Text + "\", \"Children\": ["; moel@348: nodeCount++; moel@348: moel@348: foreach (Node child in n.Nodes) moel@348: JSON += generateJSON(child) + ", "; moel@348: if (JSON.EndsWith(", ")) moel@348: JSON = JSON.Remove(JSON.LastIndexOf(",")); moel@348: JSON += "]"; moel@348: moel@348: if (n is SensorNode) moel@348: { moel@348: JSON += ", \"Min\": \"" + ((SensorNode)n).Min + "\""; moel@348: JSON += ", \"Value\": \"" + ((SensorNode)n).Value + "\""; moel@348: JSON += ", \"Max\": \"" + ((SensorNode)n).Max + "\""; moel@348: JSON += ", \"ImageURL\": \"images/transparent.png\""; moel@348: } moel@348: else if (n is HardwareNode) moel@348: { moel@348: JSON += ", \"Min\": \"\""; moel@348: JSON += ", \"Value\": \"\""; moel@348: JSON += ", \"Max\": \"\""; moel@348: JSON += ", \"ImageURL\": \"images_icon/" + getHardwareImageFile((HardwareNode)n) + "\""; moel@348: } moel@348: else if (n is TypeNode) moel@348: { moel@348: JSON += ", \"Min\": \"\""; moel@348: JSON += ", \"Value\": \"\""; moel@348: JSON += ", \"Max\": \"\""; moel@348: JSON += ", \"ImageURL\": \"images_icon/" + getTypeImageFile((TypeNode)n) + "\""; moel@348: } moel@348: else moel@348: { moel@348: JSON += ", \"Min\": \"\""; moel@348: JSON += ", \"Value\": \"\""; moel@348: JSON += ", \"Max\": \"\""; moel@348: JSON += ", \"ImageURL\": \"images_icon/computer.png\""; moel@348: } moel@348: moel@348: JSON += "}"; moel@348: return JSON; moel@348: } moel@348: moel@348: private static void returnFile(HttpListenerContext context, string filePath) moel@348: { moel@348: context.Response.ContentType = getcontentType(Path.GetExtension(filePath)); moel@348: const int bufferSize = 1024 * 512; //512KB moel@348: var buffer = new byte[bufferSize]; moel@348: using (var fs = File.OpenRead(filePath)) moel@348: { moel@348: moel@348: context.Response.ContentLength64 = fs.Length; moel@348: int read; moel@348: while ((read = fs.Read(buffer, 0, buffer.Length)) > 0) moel@348: context.Response.OutputStream.Write(buffer, 0, read); moel@348: } moel@348: moel@348: context.Response.OutputStream.Close(); moel@348: } moel@348: moel@348: private static string getcontentType(string extension) moel@348: { moel@348: switch (extension) moel@348: { moel@348: case ".avi": return "video/x-msvideo"; moel@348: case ".css": return "text/css"; moel@348: case ".doc": return "application/msword"; moel@348: case ".gif": return "image/gif"; moel@348: case ".htm": moel@348: case ".html": return "text/html"; moel@348: case ".jpg": moel@348: case ".jpeg": return "image/jpeg"; moel@348: case ".js": return "application/x-javascript"; moel@348: case ".mp3": return "audio/mpeg"; moel@348: case ".png": return "image/png"; moel@348: case ".pdf": return "application/pdf"; moel@348: case ".ppt": return "application/vnd.ms-powerpoint"; moel@348: case ".zip": return "application/zip"; moel@348: case ".txt": return "text/plain"; moel@348: default: return "application/octet-stream"; moel@348: } moel@348: } moel@348: moel@348: private static string getHardwareImageFile(HardwareNode hn) moel@348: { moel@348: moel@348: switch (hn.Hardware.HardwareType) moel@348: { moel@348: case HardwareType.CPU: moel@348: return "cpu.png"; moel@348: case HardwareType.GpuNvidia: moel@348: return "nvidia.png"; moel@348: case HardwareType.GpuAti: moel@348: return "ati.png"; moel@348: case HardwareType.HDD: moel@348: return "hdd.png"; moel@348: case HardwareType.Heatmaster: moel@348: return "bigng.png"; moel@348: case HardwareType.Mainboard: moel@348: return "mainboard.png"; moel@348: case HardwareType.SuperIO: moel@348: return "chip.png"; moel@348: case HardwareType.TBalancer: moel@348: return "bigng.png"; moel@370: case HardwareType.RAM: moel@373: return "ram.png"; moel@348: default: moel@348: return "cpu.png"; moel@348: } moel@348: moel@348: } moel@348: moel@348: private static string getTypeImageFile(TypeNode tn) moel@348: { moel@348: moel@348: switch (tn.SensorType) moel@348: { moel@348: case SensorType.Voltage: moel@348: return "voltage.png"; moel@348: case SensorType.Clock: moel@348: return "clock.png"; moel@348: case SensorType.Load: moel@348: return "load.png"; moel@348: case SensorType.Temperature: moel@348: return "temperature.png"; moel@348: case SensorType.Fan: moel@348: return "fan.png"; moel@348: case SensorType.Flow: moel@348: return "flow.png"; moel@348: case SensorType.Control: moel@348: return "control.png"; moel@348: case SensorType.Level: moel@348: return "level.png"; moel@348: case SensorType.Power: moel@348: return "power.png"; moel@348: default: moel@348: return "power.png"; moel@348: } moel@348: moel@348: } moel@348: moel@348: public int ListenerPort moel@348: { moel@348: get { return listenerPort; } moel@348: set { listenerPort = value; } moel@348: } moel@348: moel@348: ~HttpServer() moel@348: { moel@348: stopHTTPListener(); moel@348: listener.Abort(); moel@348: } moel@348: moel@348: public void Quit() moel@348: { moel@348: stopHTTPListener(); moel@348: listener.Abort(); moel@348: } moel@348: } moel@348: }