@@ -46,6 +46,9 @@ namespace Teknik | |||
bundles.Add(new CdnScriptBundle("~/bundles/markdown", config.CdnHost).Include( | |||
"~/Scripts/PageDown/Markdown.Converter.js", | |||
"~/Scripts/PageDown/Markdown.Sanitizer.js")); | |||
bundles.Add(new CdnScriptBundle("~/bundles/signalr", config.CdnHost).Include( | |||
"~/Scripts/jquery.signalR-{version}.js")); | |||
} | |||
} | |||
} |
@@ -10,6 +10,7 @@ using Teknik.Attributes; | |||
using Teknik.Controllers; | |||
using Teknik.Filters; | |||
using Teknik.Models; | |||
using Teknik.Piwik; | |||
using Teknik.Utilities; | |||
namespace Teknik.Areas.Status.Controllers | |||
@@ -29,99 +30,48 @@ namespace Teknik.Areas.Status.Controllers | |||
StatusViewModel model = new StatusViewModel(); | |||
// Load initial status info | |||
Upload.Models.Upload upload = db.Uploads.OrderByDescending(u => u.UploadId).FirstOrDefault(); | |||
model.UploadCount = (upload != null) ? upload.UploadId : 0; | |||
model.UploadSize = (upload != null) ? db.Uploads.Sum(u => (long)u.ContentLength) : 0; | |||
Paste.Models.Paste paste = db.Pastes.OrderByDescending(p => p.PasteId).FirstOrDefault(); | |||
model.PasteCount = (paste != null) ? paste.PasteId : 0; | |||
Users.Models.User user = db.Users.OrderByDescending(u => u.UserId).FirstOrDefault(); | |||
model.UserCount = (user != null) ? user.UserId : 0; | |||
Shortener.Models.ShortenedUrl url = db.ShortenedUrls.OrderByDescending(s => s.ShortenedUrlId).FirstOrDefault(); | |||
model.ShortenedUrlCount = (url != null) ? url.ShortenedUrlId : 0; | |||
Vault.Models.Vault vault = db.Vaults.OrderByDescending(v => v.VaultId).FirstOrDefault(); | |||
model.VaultCount = (url != null) ? vault.VaultId : 0; | |||
return View(model); | |||
} | |||
[HttpGet] | |||
[AllowAnonymous] | |||
public ActionResult GetUsage() | |||
public ActionResult GetVisitorData() | |||
{ | |||
try | |||
// Get the data from the Piwik | |||
if (!string.IsNullOrEmpty(Config.PiwikConfig.API)) | |||
{ | |||
float totalCPUValue = 0; | |||
float webCPUValue = 0; | |||
float dbCPUValue = 0; | |||
List<VisitorData> dataList = Reporting.GetVisitSummaryByDays(Config, 31); | |||
float totalMem = 0; | |||
float totalAvailMemValue = 0; | |||
float totalUsedMemValue = 0; | |||
float webMemValue = 0; | |||
float dbMemValue = 0; | |||
List<object> uniqueData = new List<object>(); | |||
List<object> totalData = new List<object>(); | |||
float bytesSent = 0; | |||
float bytesReceived = 0; | |||
// CPU | |||
using (PerformanceCounter totalCPU = new PerformanceCounter("Processor", "% Processor Time", "_Total", true)) | |||
using (PerformanceCounter webCPU = new PerformanceCounter("Process", "% Processor Time", Process.GetCurrentProcess().ProcessName, true)) | |||
using (PerformanceCounter dbCPU = new PerformanceCounter("Process", "% Processor Time", Config.StatusConfig.DatabaseProcessName, true)) | |||
// Memory | |||
using (PerformanceCounter totalAvailMem = new PerformanceCounter("Memory", "Available Bytes", true)) | |||
using (PerformanceCounter webMem = new PerformanceCounter("Process", "Private Bytes", Process.GetCurrentProcess().ProcessName, true)) | |||
using (PerformanceCounter dbMem = new PerformanceCounter("Process", "Private Bytes", Config.StatusConfig.DatabaseProcessName, true)) | |||
// Network | |||
using (PerformanceCounter sentPerf = new PerformanceCounter("Network Interface", "Bytes Sent/sec", Config.StatusConfig.NetworkInterface, true)) | |||
using (PerformanceCounter receivedPerf = new PerformanceCounter("Network Interface", "Bytes Received/sec", Config.StatusConfig.NetworkInterface, true)) | |||
foreach (VisitorData data in dataList.OrderBy(d => d.Date)) | |||
{ | |||
// CPU Sample | |||
totalCPU.NextValue(); | |||
if (Config.StatusConfig.ShowWebStatus) | |||
{ | |||
webCPU.NextValue(); | |||
} | |||
if (Config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
dbCPU.NextValue(); | |||
} | |||
// Network Sample | |||
sentPerf.NextValue(); | |||
receivedPerf.NextValue(); | |||
// Wait the sample time | |||
Thread.Sleep(1000); | |||
// CPU Values | |||
totalCPUValue = totalCPU.NextValue(); | |||
if (Config.StatusConfig.ShowWebStatus) | |||
{ | |||
webCPUValue = webCPU.NextValue(); | |||
} | |||
if (Config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
dbCPUValue = dbCPU.NextValue(); | |||
} | |||
// Memory Values | |||
totalMem = Config.StatusConfig.TotalMemory; | |||
totalAvailMemValue = totalAvailMem.NextValue(); | |||
totalUsedMemValue = totalMem - totalAvailMemValue; | |||
if (Config.StatusConfig.ShowWebStatus) | |||
{ | |||
webMemValue = webMem.NextValue(); | |||
} | |||
if (Config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
dbMemValue = dbMem.NextValue(); | |||
} | |||
// Network Values | |||
bytesSent = sentPerf.NextValue(); | |||
bytesReceived = receivedPerf.NextValue(); | |||
// Return usage info | |||
return Json(new { result = new { | |||
cpu = new { total = totalCPUValue, web = webCPUValue, db = dbCPUValue }, | |||
memory = new { total = totalMem, totalAvail = totalAvailMemValue, totalUsed = totalUsedMemValue, webUsed = webMemValue, dbUsed = dbMemValue }, | |||
network = new { sent = bytesSent, received = bytesReceived } | |||
} }, JsonRequestBehavior.AllowGet); | |||
object uniqueDay = new { x = Convert.ToInt64((data.Date.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds), y = data.UniqueVisitors }; | |||
uniqueData.Add(uniqueDay); | |||
object totalDay = new { x = Convert.ToInt64((data.Date.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds), y = data.Visits }; | |||
totalData.Add(totalDay); | |||
} | |||
return Json(new { result = new { uniqueVisitors = uniqueData.ToArray(), totalVisitors = totalData.ToArray() } }, JsonRequestBehavior.AllowGet); | |||
} | |||
catch (Exception ex) | |||
{ | |||
return Json(new { error = new { message = ex.GetFullMessage(true) } }, JsonRequestBehavior.AllowGet); | |||
} | |||
return Json(new { error = new { message = "Piwik not configured" } }, JsonRequestBehavior.AllowGet); | |||
} | |||
} | |||
} |
@@ -3,6 +3,9 @@ var memUsageChart; | |||
var networkUsageChart; | |||
$(document).ready(function () { | |||
/* ---------------------------------------- | |||
CPU Usage | |||
-----------------------------------------*/ | |||
cpuUsageChart = new Highcharts.chart({ | |||
chart: { | |||
useUTC: false, | |||
@@ -51,6 +54,9 @@ $(document).ready(function () { | |||
] | |||
}); | |||
/* ---------------------------------------- | |||
Memory usage | |||
-----------------------------------------*/ | |||
memUsageChart = new Highcharts.chart({ | |||
chart: { | |||
useUTC: false, | |||
@@ -108,6 +114,9 @@ $(document).ready(function () { | |||
] | |||
}); | |||
/* ---------------------------------------- | |||
Network Usage | |||
-----------------------------------------*/ | |||
networkUsageChart = new Highcharts.chart({ | |||
chart: { | |||
useUTC: false, | |||
@@ -159,58 +168,110 @@ $(document).ready(function () { | |||
] | |||
}); | |||
// Fire Off the request data | |||
requestData(); | |||
}); | |||
/* ---------------------------------------- | |||
Visitor History | |||
-----------------------------------------*/ | |||
visitChart = new Highcharts.chart({ | |||
chart: { | |||
renderTo: 'visitor-chart' | |||
}, | |||
title: { | |||
text: 'Daily Visitors' | |||
}, | |||
xAxis: { | |||
type: 'datetime', | |||
dateTimeLabelFormats: { // don't display the dummy year | |||
month: '%e. %b', | |||
year: '%b' | |||
}, | |||
title: { | |||
text: 'Date' | |||
} | |||
}, | |||
yAxis: { | |||
title: { | |||
text: 'Visitors' | |||
} | |||
}, | |||
tooltip: { | |||
shared: true, | |||
crosshairs: true, | |||
headerFormat: '<span style="font-size: 10px">{point.key:%B %e, %Y}</span><br/>', | |||
pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.y}</b><br/>' | |||
}, | |||
series: [ | |||
{ | |||
name: 'All Visitors', | |||
data: [] | |||
}, | |||
{ | |||
name: 'Unique Visitors', | |||
data: [] | |||
} | |||
] | |||
}); | |||
function requestData() { | |||
$.ajax({ | |||
type: "GET", | |||
url: getUsageURL, | |||
success: function (response) { | |||
if (response.result) { | |||
// Tick Time | |||
var x = (new Date()).getTime(); | |||
// CPU Usage | |||
cpuUsageChart.series[0].addPoint([x, response.result.cpu.total], false, cpuUsageChart.series[0].data.length > 20); | |||
if (showWebCPU) { | |||
cpuUsageChart.series[1].addPoint([x, response.result.cpu.web], false, cpuUsageChart.series[1].data.length > 20); | |||
} | |||
if (showDatabaseCPU) { | |||
cpuUsageChart.series[2].addPoint([x, response.result.cpu.db], false, cpuUsageChart.series[2].data.length > 20); | |||
} | |||
/* ---------------------------------------- | |||
Websocket for updating realtime stats | |||
-----------------------------------------*/ | |||
var ticker = $.connection.serverUsage; | |||
// Database Usage | |||
memUsageChart.series[0].addPoint([x, response.result.memory.totalUsed], false, memUsageChart.series[0].data.length > 20); | |||
if (showWebCPU) { | |||
memUsageChart.series[1].addPoint([x, response.result.memory.webUsed], false, memUsageChart.series[1].data.length > 20); | |||
} | |||
if (showDatabaseCPU) { | |||
memUsageChart.series[2].addPoint([x, response.result.memory.dbUsed], false, memUsageChart.series[2].data.length > 20); | |||
} | |||
ticker.client.updateServerUsage = function (serverUsage) { | |||
// Tick Time | |||
var x = (new Date()).getTime(); | |||
// Network Usage | |||
networkUsageChart.series[0].addPoint([x, response.result.network.sent], false, networkUsageChart.series[0].data.length > 20); | |||
networkUsageChart.series[1].addPoint([x, response.result.network.received], false, networkUsageChart.series[1].data.length > 20); | |||
// CPU Usage | |||
cpuUsageChart.series[0].addPoint([x, serverUsage.cpu.total], false, cpuUsageChart.series[0].data.length > 20); | |||
if (showWebCPU) { | |||
cpuUsageChart.series[1].addPoint([x, serverUsage.cpu.website], false, cpuUsageChart.series[1].data.length > 20); | |||
} | |||
if (showDatabaseCPU) { | |||
cpuUsageChart.series[2].addPoint([x, serverUsage.cpu.database], false, cpuUsageChart.series[2].data.length > 20); | |||
} | |||
// Redraw the charts | |||
cpuUsageChart.redraw(); | |||
memUsageChart.redraw(); | |||
networkUsageChart.redraw(); | |||
// Database Usage | |||
memUsageChart.series[0].addPoint([x, serverUsage.memory.used], false, memUsageChart.series[0].data.length > 20); | |||
if (showWebCPU) { | |||
memUsageChart.series[1].addPoint([x, serverUsage.memory.websiteUsed], false, memUsageChart.series[1].data.length > 20); | |||
} | |||
if (showDatabaseCPU) { | |||
memUsageChart.series[2].addPoint([x, serverUsage.memory.databaseUsed], false, memUsageChart.series[2].data.length > 20); | |||
} | |||
// call it again right away | |||
setTimeout(requestData, 100); | |||
} | |||
else { | |||
var err = response; | |||
if (response.error) { | |||
err = response.error.message; | |||
// Network Usage | |||
networkUsageChart.series[0].addPoint([x, serverUsage.network.sent], false, networkUsageChart.series[0].data.length > 20); | |||
networkUsageChart.series[1].addPoint([x, serverUsage.network.received], false, networkUsageChart.series[1].data.length > 20); | |||
// Redraw the charts | |||
cpuUsageChart.redraw(); | |||
memUsageChart.redraw(); | |||
networkUsageChart.redraw(); | |||
} | |||
$.connection.hub.start(); | |||
/* ---------------------------------------- | |||
Load the data for Visitor History | |||
-----------------------------------------*/ | |||
if (showVisitorStats) { | |||
$.ajax({ | |||
type: "GET", | |||
url: getVisitorDataURL, | |||
success: function (response) { | |||
if (response.result) { | |||
visitChart.series[0].setData(response.result.totalVisitors); | |||
visitChart.series[1].setData(response.result.uniqueVisitors); | |||
} | |||
else { | |||
var err = response; | |||
if (response.error) { | |||
err = response.error.message; | |||
} | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + err + '</div>'); | |||
} | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + err + '</div>'); | |||
} | |||
}, | |||
cache: false | |||
}); | |||
} | |||
}); | |||
} | |||
}); |
@@ -2,11 +2,33 @@ | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using Teknik.Models; | |||
using Teknik.ViewModels; | |||
namespace Teknik.Areas.Status.ViewModels | |||
{ | |||
public class StatusViewModel : ViewModelBase | |||
{ | |||
public int UploadCount { get; set; } | |||
public long UploadSize { get; set; } | |||
public int PasteCount { get; set; } | |||
public int UserCount { get; set; } | |||
public int ShortenedUrlCount { get; set; } | |||
public int VaultCount { get; set; } | |||
public StatusViewModel() | |||
{ | |||
UploadCount = 0; | |||
UploadSize = 0; | |||
PasteCount = 0; | |||
UserCount = 0; | |||
ShortenedUrlCount = 0; | |||
VaultCount = 0; | |||
} | |||
} | |||
} |
@@ -1,16 +1,20 @@ | |||
@model Teknik.Areas.Status.ViewModels.StatusViewModel | |||
@using Teknik.Utilities | |||
@using Newtonsoft.Json | |||
@Scripts.Render("~/bundles/signalr") | |||
@Scripts.Render("~/signalr/hubs") | |||
@Scripts.Render("~/bundles/status") | |||
<script type="text/javascript"> | |||
var getVisitorDataURL = '@Url.SubRouteUrl("status", "Status.Action", new { action = "GetVisitorData" })'; | |||
var showWebCPU = @Model.Config.StatusConfig.ShowWebStatus.ToString().ToLower(); | |||
var showDatabaseCPU = @Model.Config.StatusConfig.ShowDatabaseStatus.ToString().ToLower(); | |||
var showNetworkUsage = @Model.Config.StatusConfig.ShowNetworkStatus.ToString().ToLower(); | |||
var showVisitorStats = @Model.Config.PiwikConfig.Enabled.ToString().ToLower(); | |||
var totalMemory = @Model.Config.StatusConfig.TotalMemory; | |||
var tickInterval = totalMemory / 5; | |||
var getUsageURL = '@Url.SubRouteUrl("status", "Status.Action", new { action = "GetUsage" })'; | |||
</script> | |||
<div class="container"> | |||
@@ -18,7 +22,7 @@ | |||
{ | |||
<div class="row"> | |||
<div class="col-sm-10 col-sm-offset-1"> | |||
<h2 class="text-center"><b>Server Status</b></h2> | |||
<h2 class="text-center"><b>Realtime Usage</b></h2> | |||
<hr> | |||
<div class="row"> | |||
<div class="col-sm-12"> | |||
@@ -37,6 +41,47 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-10 col-sm-offset-1"> | |||
<br /> | |||
<h2 class="text-center"><b>Statistics</b></h2> | |||
<hr> | |||
@if (Model.Config.PiwikConfig.Enabled) | |||
{ | |||
<div class="row"> | |||
<div class="col-sm-12"> | |||
<div id="visitor-chart"></div> | |||
</div> | |||
</div> | |||
<br /> | |||
} | |||
<div class="row"> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Uploads</h3> | |||
<p>Total Count: @Model.UploadCount</p> | |||
<p>Total Size: @StringHelper.GetBytesReadable(Model.UploadSize)</p> | |||
</div> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Pastes</h3> | |||
<p>Total Count: @Model.PasteCount</p> | |||
</div> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Shortened Urls</h3> | |||
<p>Total Count: @Model.ShortenedUrlCount</p> | |||
</div> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Vaults</h3> | |||
<p>Total Count: @Model.ShortenedUrlCount</p> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-12 text-center"> | |||
<h3>Users</h3> | |||
<p>Number of Users: @Model.UserCount</p> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
} | |||
else | |||
{ |
@@ -9,19 +9,7 @@ using Teknik.ViewModels; | |||
namespace Teknik.Areas.Transparency.ViewModels | |||
{ | |||
public class TransparencyViewModel : ViewModelBase | |||
{ | |||
public int UploadCount { get; set; } | |||
public long UploadSize { get; set; } | |||
public int PasteCount { get; set; } | |||
public int UserCount { get; set; } | |||
public int ShortenedUrlCount { get; set; } | |||
public int VaultCount { get; set; } | |||
{ | |||
public string Canary { get; set; } | |||
public Dictionary<string, double> TotalBills { get; set; } |
@@ -18,51 +18,11 @@ | |||
<h2 class="text-center"><b>Behind the Scenes</b></h2> | |||
<hr> | |||
<p> | |||
Here you can view all of Teknik's financial information, takedown requests and the actions we took, as well as some general statistics for the site's services. | |||
Here you can view all of Teknik's financial information, takedown requests and the actions we took. | |||
</p> | |||
<p> | |||
If you would like to request additional information about Teknik, please feel free to contact us through our <a href="@Url.SubRouteUrl("contact", "Contact.Index")" target="_blank">Contact Form</a> or by emailing us at <a href="mailto:@Model.Config.SupportEmail">@Model.Config.SupportEmail</a>. | |||
</p> | |||
<p> | |||
Want to make a donation? Visit our <a href="@Url.SubRouteUrl("about", "About.Index")" target="_blank">About Page</a> and choose a donation method at the bottom. | |||
</p> | |||
<br /> | |||
<h2 class="text-center"><b>Statistics</b></h2> | |||
<hr> | |||
@if (Model.Config.PiwikConfig.Enabled) | |||
{ | |||
<div class="row"> | |||
<div class="col-sm-12"> | |||
<div id="visitor-chart"></div> | |||
</div> | |||
</div> | |||
<br /> | |||
} | |||
<div class="row"> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Uploads</h3> | |||
<p>Total Count: @Model.UploadCount</p> | |||
<p>Total Size: @StringHelper.GetBytesReadable(Model.UploadSize)</p> | |||
</div> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Pastes</h3> | |||
<p>Total Count: @Model.PasteCount</p> | |||
</div> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Shortened Urls</h3> | |||
<p>Total Count: @Model.ShortenedUrlCount</p> | |||
</div> | |||
<div class="col-sm-3 text-center"> | |||
<h3>Vaults</h3> | |||
<p>Total Count: @Model.ShortenedUrlCount</p> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-12 text-center"> | |||
<h3>Users</h3> | |||
<p>Number of Users: @Model.UserCount</p> | |||
</div> | |||
</div> | |||
<br /> | |||
<h2 class="text-center"><b>Transactions</b></h2> | |||
<hr> |
@@ -0,0 +1,98 @@ | |||
using Microsoft.AspNet.SignalR; | |||
using Microsoft.AspNet.SignalR.Hubs; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.Linq; | |||
using System.Threading; | |||
using System.Web; | |||
using Teknik.Configuration; | |||
using Teknik.SignalR; | |||
namespace Teknik.Hubs | |||
{ | |||
[HubName("serverUsage")] | |||
public class ServerUsageHub : Hub | |||
{ | |||
private readonly ServerUsageTicker _serverUsageTicker; | |||
public ServerUsageHub() : this(ServerUsageTicker.Instance) { } | |||
public ServerUsageHub(ServerUsageTicker serverUsageTicker) | |||
{ | |||
_serverUsageTicker = serverUsageTicker; | |||
} | |||
public class ServerUsage | |||
{ | |||
[JsonProperty("cpu")] | |||
public CPUUsage CPU { get; set; } | |||
[JsonProperty("memory")] | |||
public MemoryUsage Memory { get; set; } | |||
[JsonProperty("network")] | |||
public NetworkUsage Network { get; set; } | |||
public ServerUsage() | |||
{ | |||
CPU = new CPUUsage(); | |||
Memory = new MemoryUsage(); | |||
Network = new NetworkUsage(); | |||
} | |||
} | |||
public class CPUUsage | |||
{ | |||
[JsonProperty("total")] | |||
public float Total { get; set; } | |||
[JsonProperty("website")] | |||
public float Website { get; set; } | |||
[JsonProperty("database")] | |||
public float Database { get; set; } | |||
public CPUUsage() | |||
{ | |||
Total = 0; | |||
Website = 0; | |||
Database = 0; | |||
} | |||
} | |||
public class MemoryUsage | |||
{ | |||
[JsonProperty("total")] | |||
public float Total { get; set; } | |||
[JsonProperty("available")] | |||
public float Available { get; set; } | |||
[JsonProperty("used")] | |||
public float Used { get; set; } | |||
[JsonProperty("websiteUsed")] | |||
public float WebsiteUsed { get; set; } | |||
[JsonProperty("databaseUsed")] | |||
public float DatabaseUsed { get; set; } | |||
public MemoryUsage() | |||
{ | |||
Total = 0; | |||
Available = 0; | |||
Used = 0; | |||
WebsiteUsed = 0; | |||
DatabaseUsed = 0; | |||
} | |||
} | |||
public class NetworkUsage | |||
{ | |||
[JsonProperty("sent")] | |||
public float Sent { get; set; } | |||
[JsonProperty("received")] | |||
public float Received { get; set; } | |||
public NetworkUsage() | |||
{ | |||
Sent = 0; | |||
Received = 0; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
namespace Teknik.Models | |||
{ | |||
public class DataPoint | |||
{ | |||
public long X { get; set; } | |||
public long Y { get; set; } | |||
public DataPoint() : this(0, 0) | |||
{ | |||
} | |||
public DataPoint(long x, long y) | |||
{ | |||
X = x; | |||
Y = y; | |||
} | |||
} | |||
} |
@@ -0,0 +1,179 @@ | |||
using Microsoft.AspNet.SignalR; | |||
using Microsoft.AspNet.SignalR.Hubs; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.Linq; | |||
using System.Threading; | |||
using System.Timers; | |||
using System.Web; | |||
using Teknik.Configuration; | |||
using Teknik.Hubs; | |||
using static Teknik.Hubs.ServerUsageHub; | |||
namespace Teknik.SignalR | |||
{ | |||
public class ServerUsageTicker | |||
{ | |||
// Singleton instance | |||
private readonly static Lazy<ServerUsageTicker> _instance = new Lazy<ServerUsageTicker>(() => new ServerUsageTicker(GlobalHost.ConnectionManager.GetHubContext<ServerUsageHub>().Clients)); | |||
private readonly ServerUsage _serverUsage = new ServerUsage(); | |||
private readonly object _updateServerUsageLock = new object(); | |||
private readonly double _updateInterval = 100; | |||
private readonly System.Timers.Timer _timer; | |||
private volatile bool _updatingServerUpdates = false; | |||
public ServerUsageTicker(IHubConnectionContext<dynamic> clients) | |||
{ | |||
Clients = clients; | |||
_timer = new System.Timers.Timer(_updateInterval); | |||
_timer.Elapsed += UpdateServerUsage; | |||
_timer.AutoReset = false; | |||
_timer.Enabled = true; | |||
} | |||
public static ServerUsageTicker Instance | |||
{ | |||
get | |||
{ | |||
return _instance.Value; | |||
} | |||
} | |||
private IHubConnectionContext<dynamic> Clients | |||
{ | |||
get; | |||
set; | |||
} | |||
private void UpdateServerUsage(object source, ElapsedEventArgs e) | |||
{ | |||
lock (_updateServerUsageLock) | |||
{ | |||
if (!_updatingServerUpdates) | |||
{ | |||
_updatingServerUpdates = true; | |||
// Update Server Usage | |||
if (TryUpdateServerUsage()) | |||
{ | |||
BroadcastServerUsage(_serverUsage); | |||
} | |||
_updatingServerUpdates = false; | |||
// Restart the timer | |||
_timer.Enabled = true; | |||
} | |||
} | |||
} | |||
private void BroadcastServerUsage(ServerUsage serverUsage) | |||
{ | |||
Clients.All.updateServerUsage(serverUsage); | |||
} | |||
private bool TryUpdateServerUsage() | |||
{ | |||
try | |||
{ | |||
Config config = Config.Load(); | |||
// CPU | |||
PerformanceCounter totalCPU = new PerformanceCounter(); | |||
PerformanceCounter webCPU = new PerformanceCounter(); | |||
PerformanceCounter dbCPU = new PerformanceCounter(); | |||
// Memory | |||
PerformanceCounter totalAvailMem = new PerformanceCounter(); | |||
PerformanceCounter webMem = new PerformanceCounter(); | |||
PerformanceCounter dbMem = new PerformanceCounter(); | |||
// Network | |||
PerformanceCounter sentPerf = new PerformanceCounter(); | |||
PerformanceCounter receivedPerf = new PerformanceCounter(); | |||
string processName = Process.GetCurrentProcess().ProcessName; | |||
// CPU | |||
totalCPU = new PerformanceCounter("Processor", "% Processor Time", "_Total", true); | |||
webCPU = new PerformanceCounter("Process", "% Processor Time", processName, true); | |||
if (config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
dbCPU = new PerformanceCounter("Process", "% Processor Time", config.StatusConfig.DatabaseProcessName, true); | |||
} | |||
// Memory | |||
totalAvailMem = new PerformanceCounter("Memory", "Available Bytes", true); | |||
webMem = new PerformanceCounter("Process", "Private Bytes", processName, true); | |||
if (config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
dbMem = new PerformanceCounter("Process", "Private Bytes", config.StatusConfig.DatabaseProcessName, true); | |||
} | |||
// Network | |||
if (config.StatusConfig.ShowNetworkStatus) | |||
{ | |||
sentPerf = new PerformanceCounter("Network Interface", "Bytes Sent/sec", config.StatusConfig.NetworkInterface, true); | |||
receivedPerf = new PerformanceCounter("Network Interface", "Bytes Received/sec", config.StatusConfig.NetworkInterface, true); | |||
} | |||
// CPU Sample | |||
totalCPU.NextValue(); | |||
if (config.StatusConfig.ShowWebStatus) | |||
{ | |||
webCPU.NextValue(); | |||
} | |||
if (config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
dbCPU.NextValue(); | |||
} | |||
// Network Sample | |||
sentPerf.NextValue(); | |||
receivedPerf.NextValue(); | |||
// Wait the sample time | |||
Thread.Sleep(1000); | |||
// CPU Values | |||
_serverUsage.CPU.Total = totalCPU.NextValue(); | |||
if (config.StatusConfig.ShowWebStatus) | |||
{ | |||
_serverUsage.CPU.Website = webCPU.NextValue(); | |||
} | |||
if (config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
_serverUsage.CPU.Database = dbCPU.NextValue(); | |||
} | |||
// Memory Values | |||
_serverUsage.Memory.Total = config.StatusConfig.TotalMemory; | |||
_serverUsage.Memory.Available = totalAvailMem.NextValue(); | |||
_serverUsage.Memory.Used = _serverUsage.Memory.Total - _serverUsage.Memory.Available; | |||
if (config.StatusConfig.ShowWebStatus) | |||
{ | |||
_serverUsage.Memory.WebsiteUsed = webMem.NextValue(); | |||
} | |||
if (config.StatusConfig.ShowDatabaseStatus) | |||
{ | |||
_serverUsage.Memory.DatabaseUsed = dbMem.NextValue(); | |||
} | |||
// Network Values | |||
if (config.StatusConfig.ShowNetworkStatus) | |||
{ | |||
_serverUsage.Network.Sent = sentPerf.NextValue(); | |||
_serverUsage.Network.Received = receivedPerf.NextValue(); | |||
} | |||
return true; | |||
} | |||
catch (Exception ex) | |||
{ | |||
Logging.Logger.WriteEntry(ex); | |||
} | |||
return false; | |||
} | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
using System; | |||
using System.Threading.Tasks; | |||
using Microsoft.Owin; | |||
using Owin; | |||
[assembly: OwinStartup(typeof(Teknik.Startup))] | |||
namespace Teknik | |||
{ | |||
public class Startup | |||
{ | |||
public void Configuration(IAppBuilder app) | |||
{ | |||
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888 | |||
app.MapSignalR(); | |||
} | |||
} | |||
} |
@@ -73,11 +73,31 @@ | |||
<HintPath>..\packages\Microsoft.AspNet.Identity.EntityFramework.2.2.1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=2.2.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.2.2.1\lib\net45\Microsoft.AspNet.SignalR.Core.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb, Version=2.2.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.2.2.1\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.Azure.KeyVault.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.Azure.KeyVault.Core.2.0.4\lib\net45\Microsoft.Azure.KeyVault.Core.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="Microsoft.Owin, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.Owin.2.1.0\lib\net45\Microsoft.Owin.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.Owin.Host.SystemWeb, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.2.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.Owin.Security, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.Owin.Security.2.1.0\lib\net45\Microsoft.Owin.Security.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.VisualBasic" /> | |||
<Reference Include="MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll</HintPath> | |||
@@ -91,6 +111,10 @@ | |||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Piwik.Tracker, Version=2.16.0.0, Culture=neutral, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Piwik.Tracker.2.16.0.0\lib\net40\Piwik.Tracker.dll</HintPath> | |||
<Private>True</Private> | |||
@@ -253,6 +277,8 @@ | |||
<Compile Include="Areas\Vault\ViewModels\VaultItemViewModel.cs" /> | |||
<Compile Include="Attributes\TeknikAuthorizeAttribute.cs" /> | |||
<Compile Include="Filters\CORSActionFilter.cs" /> | |||
<Compile Include="Hubs\ServerUsageHub.cs" /> | |||
<Compile Include="Models\DataPoint.cs" /> | |||
<Compile Include="Models\TransferTypes.cs" /> | |||
<Compile Include="Areas\User\Models\UploadSettings.cs" /> | |||
<Compile Include="Areas\User\Models\UserSettings.cs" /> | |||
@@ -319,6 +345,8 @@ | |||
<Compile Include="Areas\User\ViewModels\LoginViewModel.cs" /> | |||
<Compile Include="Areas\User\ViewModels\RegisterViewModel.cs" /> | |||
<Compile Include="Modules\PerformanceMonitorModule.cs" /> | |||
<Compile Include="SignalR\ServerUsageTicker.cs" /> | |||
<Compile Include="Startup.cs" /> | |||
<Compile Include="ViewModels\ViewModelBase.cs" /> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
<Compile Include="App_Start\SubdomainRoute.cs" /> | |||
@@ -619,6 +647,8 @@ | |||
<Content Include="Scripts\jquery.blockUI.js" /> | |||
<Content Include="Scripts\jquery.fileupload.js" /> | |||
<Content Include="Scripts\jquery.iframe-transport.js" /> | |||
<Content Include="Scripts\jquery.signalR-2.2.1.js" /> | |||
<Content Include="Scripts\jquery.signalR-2.2.1.min.js" /> | |||
<Content Include="Scripts\jquery.tocify.min.js" /> | |||
<None Include="Scripts\jquery.validate-vsdoc.js" /> | |||
<Content Include="Scripts\jquery.validate.js" /> |
@@ -18,15 +18,23 @@ | |||
<package id="Microsoft.AspNet.Identity.EntityFramework" version="2.2.1" targetFramework="net452" userInstalled="true" /> | |||
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.AspNet.SignalR" version="2.2.1" targetFramework="net462" /> | |||
<package id="Microsoft.AspNet.SignalR.Core" version="2.2.1" targetFramework="net462" /> | |||
<package id="Microsoft.AspNet.SignalR.JS" version="2.2.1" targetFramework="net462" /> | |||
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.2.1" targetFramework="net462" /> | |||
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.Azure.KeyVault.Core" version="2.0.4" targetFramework="net462" /> | |||
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.Owin" version="2.1.0" targetFramework="net462" /> | |||
<package id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" targetFramework="net462" /> | |||
<package id="Microsoft.Owin.Security" version="2.1.0" targetFramework="net462" /> | |||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net46" userInstalled="true" /> | |||
<package id="Modernizr" version="2.8.3" targetFramework="net452" userInstalled="true" /> | |||
<package id="MySql.Data" version="6.9.9" targetFramework="net452" /> | |||
<package id="nClam" version="2.0.6.0" targetFramework="net462" /> | |||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" userInstalled="true" /> | |||
<package id="Owin" version="1.0" targetFramework="net462" /> | |||
<package id="Piwik.Tracker" version="2.16.0.0" targetFramework="net452" /> | |||
<package id="QRCoder" version="1.2.3" targetFramework="net462" /> | |||
<package id="Respond" version="1.4.2" targetFramework="net452" userInstalled="true" /> |