mirror of
https://github.com/aaru-dps/Aaru.Server.git
synced 2025-12-16 19:24:27 +00:00
Refactor.
This commit is contained in:
@@ -41,7 +41,7 @@ namespace DiscImageChef.Server.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private IWebHostEnvironment _environment;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
public HomeController(IWebHostEnvironment environment)
|
||||
{
|
||||
@@ -52,10 +52,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("README")]
|
||||
public ActionResult Index()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "README.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "README.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")");
|
||||
@@ -70,10 +70,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("Changelog")]
|
||||
public ActionResult Changelog()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "Changelog.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "Changelog.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")");
|
||||
@@ -88,10 +88,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("CODE_OF_CONDUCT")]
|
||||
public ActionResult CODE_OF_CONDUCT()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "CODE_OF_CONDUCT.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "CODE_OF_CONDUCT.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")").Replace("(.github/", "(");
|
||||
@@ -106,10 +106,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("PULL_REQUEST_TEMPLATE")]
|
||||
public ActionResult PULL_REQUEST_TEMPLATE()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "PULL_REQUEST_TEMPLATE.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "PULL_REQUEST_TEMPLATE.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")").Replace("(.github/", "(");
|
||||
@@ -124,10 +124,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("ISSUE_TEMPLATE")]
|
||||
public ActionResult ISSUE_TEMPLATE()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "ISSUE_TEMPLATE.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "ISSUE_TEMPLATE.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")").Replace("(.github/", "(");
|
||||
@@ -142,10 +142,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("CONTRIBUTING")]
|
||||
public ActionResult CONTRIBUTING()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "CONTRIBUTING.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "CONTRIBUTING.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")").Replace("(.github/", "(");
|
||||
@@ -160,10 +160,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("DONATING")]
|
||||
public ActionResult DONATING()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "DONATING.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "DONATING.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")");
|
||||
@@ -178,10 +178,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
[Route("TODO")]
|
||||
public ActionResult TODO()
|
||||
{
|
||||
StreamReader sr =
|
||||
var sr =
|
||||
new StreamReader(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"docs", "TODO.md"));
|
||||
string mdcontent = sr.ReadToEnd();
|
||||
"docs", "TODO.md"));
|
||||
var mdcontent = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
|
||||
mdcontent = mdcontent.Replace(".md)", ")");
|
||||
|
||||
@@ -39,97 +39,99 @@ using DiscImageChef.Decoders.SCSI;
|
||||
using DiscImageChef.Server.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Tuple = DiscImageChef.Decoders.PCMCIA.Tuple;
|
||||
|
||||
namespace DiscImageChef.Server.Controllers
|
||||
{
|
||||
public class ReportController : Controller
|
||||
{
|
||||
private DicServerContext _ctx;
|
||||
private readonly DicServerContext _ctx;
|
||||
|
||||
public ReportController(DicServerContext context)
|
||||
{
|
||||
_ctx = context;
|
||||
}
|
||||
|
||||
public ActionResult Index() => RedirectToAction("View", "Report", new RouteValueDictionary {{"id", 1}});
|
||||
public ActionResult Index()
|
||||
{
|
||||
return RedirectToAction("View", "Report", new RouteValueDictionary {{"id", 1}});
|
||||
}
|
||||
|
||||
public ActionResult View(int? id)
|
||||
{
|
||||
if(id == null || id <= 0) return Content("Incorrect device report request");
|
||||
if (id == null || id <= 0) return Content("Incorrect device report request");
|
||||
|
||||
try
|
||||
{
|
||||
Device report = _ctx.Devices.FirstOrDefault(d => d.Id == id);
|
||||
var report = _ctx.Devices.FirstOrDefault(d => d.Id == id);
|
||||
|
||||
if(report is null) return Content("Cannot find requested report");
|
||||
if (report is null) return Content("Cannot find requested report");
|
||||
|
||||
ViewBag.lblManufacturer = report.Manufacturer;
|
||||
ViewBag.lblModel = report.Model;
|
||||
ViewBag.lblRevision = report.Revision;
|
||||
ViewBag.lblModel = report.Model;
|
||||
ViewBag.lblRevision = report.Revision;
|
||||
|
||||
if(report.USB != null)
|
||||
if (report.USB != null)
|
||||
{
|
||||
string usbVendorDescription = null;
|
||||
string usbVendorDescription = null;
|
||||
string usbProductDescription = null;
|
||||
|
||||
UsbProduct dbProduct =
|
||||
_ctx.UsbProducts.FirstOrDefault(p => p.ProductId == report.USB.ProductID &&
|
||||
p.Vendor != null &&
|
||||
p.Vendor.VendorId == report.USB.VendorID);
|
||||
var dbProduct =
|
||||
_ctx.UsbProducts.FirstOrDefault(p => p.ProductId == report.USB.ProductID &&
|
||||
p.Vendor != null &&
|
||||
p.Vendor.VendorId == report.USB.VendorID);
|
||||
|
||||
if(dbProduct is null)
|
||||
if (dbProduct is null)
|
||||
{
|
||||
UsbVendor dbVendor = _ctx.UsbVendors.FirstOrDefault(v => v.VendorId == report.USB.VendorID);
|
||||
var dbVendor = _ctx.UsbVendors.FirstOrDefault(v => v.VendorId == report.USB.VendorID);
|
||||
|
||||
if(!(dbVendor is null)) usbVendorDescription = dbVendor.Vendor;
|
||||
if (!(dbVendor is null)) usbVendorDescription = dbVendor.Vendor;
|
||||
}
|
||||
else
|
||||
{
|
||||
usbProductDescription = dbProduct.Product;
|
||||
usbVendorDescription = dbProduct.Vendor.Vendor;
|
||||
usbVendorDescription = dbProduct.Vendor.Vendor;
|
||||
}
|
||||
|
||||
ViewBag.UsbItem = new Item
|
||||
{
|
||||
Manufacturer = report.USB.Manufacturer,
|
||||
Product = report.USB.Product,
|
||||
Product = report.USB.Product,
|
||||
VendorDescription =
|
||||
usbVendorDescription != null
|
||||
? $"0x{report.USB.VendorID:x4} ({usbVendorDescription})"
|
||||
: $"0x{report.USB.VendorID:x4}",
|
||||
ProductDescription = usbProductDescription != null
|
||||
? $"0x{report.USB.ProductID:x4} ({usbProductDescription})"
|
||||
: $"0x{report.USB.ProductID:x4}"
|
||||
? $"0x{report.USB.ProductID:x4} ({usbProductDescription})"
|
||||
: $"0x{report.USB.ProductID:x4}"
|
||||
};
|
||||
}
|
||||
|
||||
if(report.FireWire != null)
|
||||
if (report.FireWire != null)
|
||||
ViewBag.FireWireItem = new Item
|
||||
{
|
||||
Manufacturer = report.FireWire.Manufacturer,
|
||||
Product = report.FireWire.Product,
|
||||
VendorDescription = $"0x{report.FireWire.VendorID:x8}",
|
||||
Manufacturer = report.FireWire.Manufacturer,
|
||||
Product = report.FireWire.Product,
|
||||
VendorDescription = $"0x{report.FireWire.VendorID:x8}",
|
||||
ProductDescription = $"0x{report.FireWire.ProductID:x8}"
|
||||
};
|
||||
|
||||
if(report.PCMCIA != null)
|
||||
if (report.PCMCIA != null)
|
||||
{
|
||||
ViewBag.PcmciaItem = new PcmciaItem
|
||||
{
|
||||
Manufacturer = report.PCMCIA.Manufacturer,
|
||||
Product = report.PCMCIA.ProductName,
|
||||
VendorDescription = $"0x{report.PCMCIA.ManufacturerCode:x4}",
|
||||
Manufacturer = report.PCMCIA.Manufacturer,
|
||||
Product = report.PCMCIA.ProductName,
|
||||
VendorDescription = $"0x{report.PCMCIA.ManufacturerCode:x4}",
|
||||
ProductDescription = $"0x{report.PCMCIA.CardCode:x4}",
|
||||
Compliance = report.PCMCIA.Compliance
|
||||
Compliance = report.PCMCIA.Compliance
|
||||
};
|
||||
|
||||
Tuple[] tuples = CIS.GetTuples(report.PCMCIA.CIS);
|
||||
if(tuples != null)
|
||||
var tuples = CIS.GetTuples(report.PCMCIA.CIS);
|
||||
if (tuples != null)
|
||||
{
|
||||
Dictionary<string, string> decodedTuples = new Dictionary<string, string>();
|
||||
foreach(Tuple tuple in tuples)
|
||||
switch(tuple.Code)
|
||||
var decodedTuples = new Dictionary<string, string>();
|
||||
foreach (var tuple in tuples)
|
||||
switch (tuple.Code)
|
||||
{
|
||||
case TupleCodes.CISTPL_NULL:
|
||||
case TupleCodes.CISTPL_END:
|
||||
@@ -137,20 +139,20 @@ namespace DiscImageChef.Server.Controllers
|
||||
case TupleCodes.CISTPL_VERS_1: break;
|
||||
case TupleCodes.CISTPL_DEVICEGEO:
|
||||
case TupleCodes.CISTPL_DEVICEGEO_A:
|
||||
DeviceGeometryTuple geom = CIS.DecodeDeviceGeometryTuple(tuple.Data);
|
||||
if(geom?.Geometries != null)
|
||||
foreach(DeviceGeometry geometry in geom.Geometries)
|
||||
var geom = CIS.DecodeDeviceGeometryTuple(tuple.Data);
|
||||
if (geom?.Geometries != null)
|
||||
foreach (var geometry in geom.Geometries)
|
||||
{
|
||||
decodedTuples.Add("Device width",
|
||||
$"{(1 << (geometry.CardInterface - 1)) * 8} bits");
|
||||
$"{(1 << (geometry.CardInterface - 1)) * 8} bits");
|
||||
decodedTuples.Add("Erase block",
|
||||
$"{(1 << (geometry.EraseBlockSize - 1)) * (1 << (geometry.Interleaving - 1))} bytes");
|
||||
$"{(1 << (geometry.EraseBlockSize - 1)) * (1 << (geometry.Interleaving - 1))} bytes");
|
||||
decodedTuples.Add("Read block",
|
||||
$"{(1 << (geometry.ReadBlockSize - 1)) * (1 << (geometry.Interleaving - 1))} bytes");
|
||||
$"{(1 << (geometry.ReadBlockSize - 1)) * (1 << (geometry.Interleaving - 1))} bytes");
|
||||
decodedTuples.Add("Write block",
|
||||
$"{(1 << (geometry.WriteBlockSize - 1)) * (1 << (geometry.Interleaving - 1))} bytes");
|
||||
$"{(1 << (geometry.WriteBlockSize - 1)) * (1 << (geometry.Interleaving - 1))} bytes");
|
||||
decodedTuples.Add("Partition alignment",
|
||||
$"{(1 << (geometry.EraseBlockSize - 1)) * (1 << (geometry.Interleaving - 1)) * (1 << (geometry.Partitions - 1))} bytes");
|
||||
$"{(1 << (geometry.EraseBlockSize - 1)) * (1 << (geometry.Interleaving - 1)) * (1 << (geometry.Partitions - 1))} bytes");
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -191,44 +193,44 @@ namespace DiscImageChef.Server.Controllers
|
||||
decodedTuples.Add("Undecoded tuple ID", tuple.Code.ToString());
|
||||
break;
|
||||
default:
|
||||
decodedTuples.Add("Unknown tuple ID", $"0x{(byte)tuple.Code:X2}");
|
||||
decodedTuples.Add("Unknown tuple ID", $"0x{(byte) tuple.Code:X2}");
|
||||
break;
|
||||
}
|
||||
|
||||
if(decodedTuples.Count > 0) ViewBag.repPcmciaTuples = decodedTuples;
|
||||
if (decodedTuples.Count > 0) ViewBag.repPcmciaTuples = decodedTuples;
|
||||
}
|
||||
}
|
||||
|
||||
bool removable = true;
|
||||
var removable = true;
|
||||
List<TestedMedia> testedMedia = null;
|
||||
bool ata = false;
|
||||
bool atapi = false;
|
||||
bool sscMedia = false;
|
||||
var ata = false;
|
||||
var atapi = false;
|
||||
var sscMedia = false;
|
||||
|
||||
if(report.ATA != null || report.ATAPI != null)
|
||||
if (report.ATA != null || report.ATAPI != null)
|
||||
{
|
||||
ata = true;
|
||||
List<string> ataOneValue = new List<string>();
|
||||
Dictionary<string, string> ataTwoValue = new Dictionary<string, string>();
|
||||
CommonTypes.Metadata.Ata ataReport;
|
||||
var ataOneValue = new List<string>();
|
||||
var ataTwoValue = new Dictionary<string, string>();
|
||||
CommonTypes.Metadata.Ata ataReport;
|
||||
|
||||
if(report.ATAPI != null)
|
||||
if (report.ATAPI != null)
|
||||
{
|
||||
ViewBag.AtaItem = "ATAPI";
|
||||
ataReport = report.ATAPI;
|
||||
atapi = true;
|
||||
ataReport = report.ATAPI;
|
||||
atapi = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewBag.AtaItem = "ATA";
|
||||
ataReport = report.ATA;
|
||||
ataReport = report.ATA;
|
||||
}
|
||||
|
||||
bool cfa = report.CompactFlash;
|
||||
var cfa = report.CompactFlash;
|
||||
|
||||
if(atapi && !cfa) ViewBag.lblAtaDeviceType = "ATAPI device";
|
||||
else if(!atapi && cfa) ViewBag.lblAtaDeviceType = "CompactFlash device";
|
||||
else ViewBag.lblAtaDeviceType = "ATA device";
|
||||
if (atapi && !cfa) ViewBag.lblAtaDeviceType = "ATAPI device";
|
||||
else if (!atapi && cfa) ViewBag.lblAtaDeviceType = "CompactFlash device";
|
||||
else ViewBag.lblAtaDeviceType = "ATA device";
|
||||
|
||||
Ata.Report(ataReport, cfa, atapi, ref removable, ref ataOneValue, ref ataTwoValue, ref testedMedia);
|
||||
|
||||
@@ -236,62 +238,62 @@ namespace DiscImageChef.Server.Controllers
|
||||
ViewBag.repAtaTwo = ataTwoValue;
|
||||
}
|
||||
|
||||
if(report.SCSI != null)
|
||||
if (report.SCSI != null)
|
||||
{
|
||||
List<string> scsiOneValue = new List<string>();
|
||||
Dictionary<string, string> modePages = new Dictionary<string, string>();
|
||||
Dictionary<string, string> evpdPages = new Dictionary<string, string>();
|
||||
var scsiOneValue = new List<string>();
|
||||
var modePages = new Dictionary<string, string>();
|
||||
var evpdPages = new Dictionary<string, string>();
|
||||
|
||||
string vendorId = StringHandlers.CToString(report.SCSI.Inquiry?.VendorIdentification);
|
||||
if(report.SCSI.Inquiry != null)
|
||||
var vendorId = StringHandlers.CToString(report.SCSI.Inquiry?.VendorIdentification);
|
||||
if (report.SCSI.Inquiry != null)
|
||||
{
|
||||
Inquiry.SCSIInquiry inq = report.SCSI.Inquiry.Value;
|
||||
var inq = report.SCSI.Inquiry.Value;
|
||||
ViewBag.lblScsiVendor = VendorString.Prettify(vendorId) != vendorId
|
||||
? $"{vendorId} ({VendorString.Prettify(vendorId)})"
|
||||
: vendorId;
|
||||
ViewBag.lblScsiProduct = StringHandlers.CToString(inq.ProductIdentification);
|
||||
? $"{vendorId} ({VendorString.Prettify(vendorId)})"
|
||||
: vendorId;
|
||||
ViewBag.lblScsiProduct = StringHandlers.CToString(inq.ProductIdentification);
|
||||
ViewBag.lblScsiRevision = StringHandlers.CToString(inq.ProductRevisionLevel);
|
||||
}
|
||||
|
||||
scsiOneValue.AddRange(ScsiInquiry.Report(report.SCSI.Inquiry));
|
||||
|
||||
if(report.SCSI.SupportsModeSense6) scsiOneValue.Add("Device supports MODE SENSE (6)");
|
||||
if(report.SCSI.SupportsModeSense10) scsiOneValue.Add("Device supports MODE SENSE (10)");
|
||||
if(report.SCSI.SupportsModeSubpages) scsiOneValue.Add("Device supports MODE SENSE subpages");
|
||||
if (report.SCSI.SupportsModeSense6) scsiOneValue.Add("Device supports MODE SENSE (6)");
|
||||
if (report.SCSI.SupportsModeSense10) scsiOneValue.Add("Device supports MODE SENSE (10)");
|
||||
if (report.SCSI.SupportsModeSubpages) scsiOneValue.Add("Device supports MODE SENSE subpages");
|
||||
|
||||
if(report.SCSI.ModeSense != null)
|
||||
if (report.SCSI.ModeSense != null)
|
||||
{
|
||||
PeripheralDeviceTypes devType = PeripheralDeviceTypes.DirectAccess;
|
||||
if(report.SCSI.Inquiry != null)
|
||||
devType = (PeripheralDeviceTypes)report.SCSI.Inquiry.Value.PeripheralDeviceType;
|
||||
var devType = PeripheralDeviceTypes.DirectAccess;
|
||||
if (report.SCSI.Inquiry != null)
|
||||
devType = (PeripheralDeviceTypes) report.SCSI.Inquiry.Value.PeripheralDeviceType;
|
||||
ScsiModeSense.Report(report.SCSI.ModeSense, vendorId, devType, ref scsiOneValue, ref modePages);
|
||||
}
|
||||
|
||||
if(modePages.Count > 0) ViewBag.repModeSense = modePages;
|
||||
if (modePages.Count > 0) ViewBag.repModeSense = modePages;
|
||||
|
||||
if(report.SCSI.EVPDPages != null) ScsiEvpd.Report(report.SCSI.EVPDPages, vendorId, ref evpdPages);
|
||||
if (report.SCSI.EVPDPages != null) ScsiEvpd.Report(report.SCSI.EVPDPages, vendorId, ref evpdPages);
|
||||
|
||||
if(evpdPages.Count > 0) ViewBag.repEvpd = evpdPages;
|
||||
if (evpdPages.Count > 0) ViewBag.repEvpd = evpdPages;
|
||||
|
||||
if(report.SCSI.MultiMediaDevice != null)
|
||||
if (report.SCSI.MultiMediaDevice != null)
|
||||
{
|
||||
testedMedia = report.SCSI.MultiMediaDevice.TestedMedia;
|
||||
|
||||
if(report.SCSI.MultiMediaDevice.ModeSense2A != null)
|
||||
if (report.SCSI.MultiMediaDevice.ModeSense2A != null)
|
||||
{
|
||||
List<string> mmcModeOneValue = new List<string>();
|
||||
var mmcModeOneValue = new List<string>();
|
||||
ScsiMmcMode.Report(report.SCSI.MultiMediaDevice.ModeSense2A, ref mmcModeOneValue);
|
||||
if(mmcModeOneValue.Count > 0) ViewBag.repScsiMmcMode = mmcModeOneValue;
|
||||
if (mmcModeOneValue.Count > 0) ViewBag.repScsiMmcMode = mmcModeOneValue;
|
||||
}
|
||||
|
||||
if(report.SCSI.MultiMediaDevice.Features != null)
|
||||
if (report.SCSI.MultiMediaDevice.Features != null)
|
||||
{
|
||||
List<string> mmcFeaturesOneValue = new List<string>();
|
||||
var mmcFeaturesOneValue = new List<string>();
|
||||
ScsiMmcFeatures.Report(report.SCSI.MultiMediaDevice.Features, ref mmcFeaturesOneValue);
|
||||
if(mmcFeaturesOneValue.Count > 0) ViewBag.repScsiMmcFeatures = mmcFeaturesOneValue;
|
||||
if (mmcFeaturesOneValue.Count > 0) ViewBag.repScsiMmcFeatures = mmcFeaturesOneValue;
|
||||
}
|
||||
}
|
||||
else if(report.SCSI.SequentialDevice != null)
|
||||
else if (report.SCSI.SequentialDevice != null)
|
||||
{
|
||||
ViewBag.divScsiSscVisible = true;
|
||||
|
||||
@@ -304,160 +306,167 @@ namespace DiscImageChef.Server.Controllers
|
||||
ViewBag.lblScsiSscMinBlock =
|
||||
report.SCSI.SequentialDevice.MinBlockLength?.ToString() ?? "Unspecified";
|
||||
|
||||
if(report.SCSI.SequentialDevice.SupportedDensities != null)
|
||||
if (report.SCSI.SequentialDevice.SupportedDensities != null)
|
||||
ViewBag.repScsiSscDensities = report.SCSI.SequentialDevice.SupportedDensities;
|
||||
|
||||
if(report.SCSI.SequentialDevice.SupportedMediaTypes != null)
|
||||
if (report.SCSI.SequentialDevice.SupportedMediaTypes != null)
|
||||
ViewBag.repScsiSscMedias = report.SCSI.SequentialDevice.SupportedMediaTypes;
|
||||
|
||||
if(report.SCSI.SequentialDevice.TestedMedia != null)
|
||||
if (report.SCSI.SequentialDevice.TestedMedia != null)
|
||||
{
|
||||
List<string> mediaOneValue = new List<string>();
|
||||
var mediaOneValue = new List<string>();
|
||||
SscTestedMedia.Report(report.SCSI.SequentialDevice.TestedMedia, ref mediaOneValue);
|
||||
if(mediaOneValue.Count > 0)
|
||||
if (mediaOneValue.Count > 0)
|
||||
{
|
||||
sscMedia = true;
|
||||
sscMedia = true;
|
||||
ViewBag.repTestedMedia = mediaOneValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(report.SCSI.ReadCapabilities != null)
|
||||
else if (report.SCSI.ReadCapabilities != null)
|
||||
{
|
||||
removable = false;
|
||||
scsiOneValue.Add("");
|
||||
|
||||
if(report.SCSI.ReadCapabilities.Blocks.HasValue &&
|
||||
report.SCSI.ReadCapabilities.BlockSize.HasValue)
|
||||
if (report.SCSI.ReadCapabilities.Blocks.HasValue &&
|
||||
report.SCSI.ReadCapabilities.BlockSize.HasValue)
|
||||
{
|
||||
scsiOneValue
|
||||
.Add($"Device has {report.SCSI.ReadCapabilities.Blocks} blocks of {report.SCSI.ReadCapabilities.BlockSize} bytes each");
|
||||
.Add(
|
||||
$"Device has {report.SCSI.ReadCapabilities.Blocks} blocks of {report.SCSI.ReadCapabilities.BlockSize} bytes each");
|
||||
|
||||
if(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1024 /
|
||||
1024 > 1000000)
|
||||
if (report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1024 /
|
||||
1024 > 1000000)
|
||||
scsiOneValue
|
||||
.Add($"Device size: {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000 / 1000 / 1000} Tb, {(double)(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024 / 1024 / 1024:F2} TiB");
|
||||
else if(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize /
|
||||
1024 /
|
||||
1024 > 1000)
|
||||
.Add(
|
||||
$"Device size: {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000 / 1000 / 1000} Tb, {(double) (report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024 / 1024 / 1024:F2} TiB");
|
||||
else if (report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize /
|
||||
1024 /
|
||||
1024 > 1000)
|
||||
scsiOneValue
|
||||
.Add($"Device size: {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000 / 1000} Gb, {(double)(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024 / 1024:F2} GiB");
|
||||
.Add(
|
||||
$"Device size: {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000 / 1000} Gb, {(double) (report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024 / 1024:F2} GiB");
|
||||
else
|
||||
scsiOneValue
|
||||
.Add($"Device size: {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000} Mb, {(double)(report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024:F2} MiB");
|
||||
.Add(
|
||||
$"Device size: {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize} bytes, {report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize / 1000 / 1000} Mb, {(double) (report.SCSI.ReadCapabilities.Blocks * report.SCSI.ReadCapabilities.BlockSize) / 1024 / 1024:F2} MiB");
|
||||
}
|
||||
|
||||
if(report.SCSI.ReadCapabilities.MediumType.HasValue)
|
||||
if (report.SCSI.ReadCapabilities.MediumType.HasValue)
|
||||
scsiOneValue.Add($"Medium type code: {report.SCSI.ReadCapabilities.MediumType:X2}h");
|
||||
if(report.SCSI.ReadCapabilities.Density.HasValue)
|
||||
if (report.SCSI.ReadCapabilities.Density.HasValue)
|
||||
scsiOneValue.Add($"Density code: {report.SCSI.ReadCapabilities.Density:X2}h");
|
||||
if((report.SCSI.ReadCapabilities.SupportsReadLong == true ||
|
||||
report.SCSI.ReadCapabilities.SupportsReadLong16 == true) &&
|
||||
report.SCSI.ReadCapabilities.LongBlockSize.HasValue)
|
||||
if ((report.SCSI.ReadCapabilities.SupportsReadLong == true ||
|
||||
report.SCSI.ReadCapabilities.SupportsReadLong16 == true) &&
|
||||
report.SCSI.ReadCapabilities.LongBlockSize.HasValue)
|
||||
scsiOneValue.Add($"Long block size: {report.SCSI.ReadCapabilities.LongBlockSize} bytes");
|
||||
if(report.SCSI.ReadCapabilities.SupportsReadCapacity == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsReadCapacity == true)
|
||||
scsiOneValue.Add("Device supports READ CAPACITY (10) command.");
|
||||
if(report.SCSI.ReadCapabilities.SupportsReadCapacity16 == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsReadCapacity16 == true)
|
||||
scsiOneValue.Add("Device supports READ CAPACITY (16) command.");
|
||||
if(report.SCSI.ReadCapabilities.SupportsRead6 == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsRead6 == true)
|
||||
scsiOneValue.Add("Device supports READ (6) command.");
|
||||
if(report.SCSI.ReadCapabilities.SupportsRead10 == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsRead10 == true)
|
||||
scsiOneValue.Add("Device supports READ (10) command.");
|
||||
if(report.SCSI.ReadCapabilities.SupportsRead12 == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsRead12 == true)
|
||||
scsiOneValue.Add("Device supports READ (12) command.");
|
||||
if(report.SCSI.ReadCapabilities.SupportsRead16 == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsRead16 == true)
|
||||
scsiOneValue.Add("Device supports READ (16) command.");
|
||||
if(report.SCSI.ReadCapabilities.SupportsReadLong == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsReadLong == true)
|
||||
scsiOneValue.Add("Device supports READ LONG (10) command.");
|
||||
if(report.SCSI.ReadCapabilities.SupportsReadLong16 == true)
|
||||
if (report.SCSI.ReadCapabilities.SupportsReadLong16 == true)
|
||||
scsiOneValue.Add("Device supports READ LONG (16) command.");
|
||||
}
|
||||
else testedMedia = report.SCSI.RemovableMedias;
|
||||
else
|
||||
{
|
||||
testedMedia = report.SCSI.RemovableMedias;
|
||||
}
|
||||
|
||||
ViewBag.repScsi = scsiOneValue;
|
||||
}
|
||||
|
||||
if(report.MultiMediaCard != null)
|
||||
if (report.MultiMediaCard != null)
|
||||
{
|
||||
List<string> mmcOneValue = new List<string>();
|
||||
var mmcOneValue = new List<string>();
|
||||
|
||||
if(report.MultiMediaCard.CID != null)
|
||||
if (report.MultiMediaCard.CID != null)
|
||||
{
|
||||
mmcOneValue.Add(Decoders.MMC.Decoders.PrettifyCID(report.MultiMediaCard.CID)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
mmcOneValue.Add("");
|
||||
}
|
||||
|
||||
if(report.MultiMediaCard.CSD != null)
|
||||
if (report.MultiMediaCard.CSD != null)
|
||||
{
|
||||
mmcOneValue.Add(Decoders.MMC.Decoders.PrettifyCSD(report.MultiMediaCard.CSD)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
mmcOneValue.Add("");
|
||||
}
|
||||
|
||||
if(report.MultiMediaCard.ExtendedCSD != null)
|
||||
if (report.MultiMediaCard.ExtendedCSD != null)
|
||||
{
|
||||
mmcOneValue.Add(Decoders.MMC.Decoders.PrettifyExtendedCSD(report.MultiMediaCard.ExtendedCSD)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
mmcOneValue.Add("");
|
||||
}
|
||||
|
||||
if(report.MultiMediaCard.OCR != null)
|
||||
if (report.MultiMediaCard.OCR != null)
|
||||
{
|
||||
mmcOneValue.Add(Decoders.MMC.Decoders.PrettifyCSD(report.MultiMediaCard.OCR)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
mmcOneValue.Add("");
|
||||
}
|
||||
|
||||
ViewBag.repMMC = mmcOneValue;
|
||||
}
|
||||
|
||||
if(report.SecureDigital != null)
|
||||
if (report.SecureDigital != null)
|
||||
{
|
||||
List<string> sdOneValue = new List<string>();
|
||||
var sdOneValue = new List<string>();
|
||||
|
||||
if(report.SecureDigital.CID != null)
|
||||
if (report.SecureDigital.CID != null)
|
||||
{
|
||||
sdOneValue.Add(Decoders.SecureDigital.Decoders.PrettifyCID(report.SecureDigital.CID)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
sdOneValue.Add("");
|
||||
}
|
||||
|
||||
if(report.SecureDigital.CSD != null)
|
||||
if (report.SecureDigital.CSD != null)
|
||||
{
|
||||
sdOneValue.Add(Decoders.SecureDigital.Decoders.PrettifyCSD(report.SecureDigital.CSD)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
sdOneValue.Add("");
|
||||
}
|
||||
|
||||
if(report.SecureDigital.SCR != null)
|
||||
if (report.SecureDigital.SCR != null)
|
||||
{
|
||||
sdOneValue.Add(Decoders.SecureDigital.Decoders.PrettifySCR(report.SecureDigital.SCR)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
sdOneValue.Add("");
|
||||
}
|
||||
|
||||
if(report.SecureDigital.OCR != null)
|
||||
if (report.SecureDigital.OCR != null)
|
||||
{
|
||||
sdOneValue.Add(Decoders.SecureDigital.Decoders.PrettifyCSD(report.SecureDigital.OCR)
|
||||
.Replace("\n", "<br/>"));
|
||||
.Replace("\n", "<br/>"));
|
||||
sdOneValue.Add("");
|
||||
}
|
||||
|
||||
ViewBag.repSD = sdOneValue;
|
||||
}
|
||||
|
||||
if(removable && !sscMedia && testedMedia != null)
|
||||
if (removable && !sscMedia && testedMedia != null)
|
||||
{
|
||||
List<string> mediaOneValue = new List<string>();
|
||||
var mediaOneValue = new List<string>();
|
||||
App_Start.TestedMedia.Report(testedMedia, ref mediaOneValue);
|
||||
if(mediaOneValue.Count > 0) ViewBag.repTestedMedia = mediaOneValue;
|
||||
if (mediaOneValue.Count > 0) ViewBag.repTestedMedia = mediaOneValue;
|
||||
}
|
||||
}
|
||||
catch(Exception)
|
||||
catch (Exception)
|
||||
{
|
||||
#if DEBUG
|
||||
#if DEBUG
|
||||
throw;
|
||||
#endif
|
||||
#endif
|
||||
return Content("Could not load device report");
|
||||
}
|
||||
|
||||
|
||||
@@ -44,11 +44,7 @@ using DiscImageChef.Server.Models;
|
||||
using Highsoft.Web.Mvc.Charts;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Hosting.Internal;
|
||||
using Filter = DiscImageChef.Server.Models.Filter;
|
||||
using OperatingSystem = DiscImageChef.Server.Models.OperatingSystem;
|
||||
using PlatformID = DiscImageChef.CommonTypes.Interop.PlatformID;
|
||||
using Version = DiscImageChef.Server.Models.Version;
|
||||
|
||||
namespace DiscImageChef.Server.Controllers
|
||||
{
|
||||
@@ -57,13 +53,13 @@ namespace DiscImageChef.Server.Controllers
|
||||
/// </summary>
|
||||
public class StatsController : Controller
|
||||
{
|
||||
DicServerContext ctx;
|
||||
List<DeviceItem> devices;
|
||||
List<NameValueStats> operatingSystems;
|
||||
List<MediaItem> realMedia;
|
||||
List<NameValueStats> versions;
|
||||
List<MediaItem> virtualMedia;
|
||||
private IWebHostEnvironment _environment;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly DicServerContext ctx;
|
||||
private List<DeviceItem> devices;
|
||||
private List<NameValueStats> operatingSystems;
|
||||
private List<MediaItem> realMedia;
|
||||
private List<NameValueStats> versions;
|
||||
private List<MediaItem> virtualMedia;
|
||||
|
||||
public StatsController(IWebHostEnvironment environment, DicServerContext context)
|
||||
{
|
||||
@@ -77,118 +73,120 @@ namespace DiscImageChef.Server.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
if(
|
||||
if (
|
||||
System.IO.File
|
||||
.Exists(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Statistics", "Statistics.xml")))
|
||||
.Exists(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Statistics", "Statistics.xml")))
|
||||
try
|
||||
{
|
||||
Stats statistics = new Stats();
|
||||
var statistics = new Stats();
|
||||
|
||||
XmlSerializer xs = new XmlSerializer(statistics.GetType());
|
||||
FileStream fs =
|
||||
WaitForFile(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(), "Statistics", "Statistics.xml"),
|
||||
FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
statistics = (Stats)xs.Deserialize(fs);
|
||||
var xs = new XmlSerializer(statistics.GetType());
|
||||
var fs =
|
||||
WaitForFile(
|
||||
Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Statistics", "Statistics.xml"),
|
||||
FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
statistics = (Stats) xs.Deserialize(fs);
|
||||
fs.Close();
|
||||
|
||||
StatsConverter.Convert(statistics);
|
||||
|
||||
System.IO.File
|
||||
.Delete(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Statistics", "Statistics.xml"));
|
||||
.Delete(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Statistics", "Statistics.xml"));
|
||||
}
|
||||
catch(XmlException)
|
||||
catch (XmlException)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if(ctx.OperatingSystems.Any())
|
||||
if (ctx.OperatingSystems.Any())
|
||||
{
|
||||
operatingSystems = new List<NameValueStats>();
|
||||
foreach(OperatingSystem nvs in ctx.OperatingSystems)
|
||||
foreach (var nvs in ctx.OperatingSystems)
|
||||
operatingSystems.Add(new NameValueStats
|
||||
{
|
||||
name =
|
||||
$"{DetectOS.GetPlatformName((PlatformID)Enum.Parse(typeof(PlatformID), nvs.Name), nvs.Version)}{(string.IsNullOrEmpty(nvs.Version) ? "" : " ")}{nvs.Version}",
|
||||
$"{DetectOS.GetPlatformName((PlatformID) Enum.Parse(typeof(PlatformID), nvs.Name), nvs.Version)}{(string.IsNullOrEmpty(nvs.Version) ? "" : " ")}{nvs.Version}",
|
||||
Value = nvs.Count
|
||||
});
|
||||
|
||||
ViewBag.repOperatingSystems = operatingSystems.OrderBy(os => os.name).ToList();
|
||||
|
||||
List<PieSeriesData> osPieData = new List<PieSeriesData>();
|
||||
var osPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal totalOsCount = ctx.OperatingSystems.Sum(o => o.Count);
|
||||
foreach(string os in ctx.OperatingSystems.Select(o => o.Name).Distinct().ToList())
|
||||
foreach (var os in ctx.OperatingSystems.Select(o => o.Name).Distinct().ToList())
|
||||
{
|
||||
decimal osCount = ctx.OperatingSystems.Where(o => o.Name == os).Sum(o => o.Count);
|
||||
|
||||
osPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name =
|
||||
DetectOS.GetPlatformName((PlatformID)Enum.Parse(typeof(PlatformID),
|
||||
os)),
|
||||
Y = (double?)(osCount / totalOsCount),
|
||||
Sliced = os == "Linux",
|
||||
DetectOS.GetPlatformName((PlatformID) Enum.Parse(typeof(PlatformID),
|
||||
os)),
|
||||
Y = (double?) (osCount / totalOsCount),
|
||||
Sliced = os == "Linux",
|
||||
Selected = os == "Linux"
|
||||
});
|
||||
}
|
||||
|
||||
ViewData["osPieData"] = osPieData;
|
||||
|
||||
List<PieSeriesData> linuxPieData = new List<PieSeriesData>();
|
||||
var linuxPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal linuxCount = ctx.OperatingSystems.Where(o => o.Name == PlatformID.Linux.ToString())
|
||||
.Sum(o => o.Count);
|
||||
foreach(OperatingSystem version in
|
||||
.Sum(o => o.Count);
|
||||
foreach (var version in
|
||||
ctx.OperatingSystems.Where(o => o.Name == PlatformID.Linux.ToString()))
|
||||
linuxPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name =
|
||||
$"{DetectOS.GetPlatformName(PlatformID.Linux, version.Version)}{(string.IsNullOrEmpty(version.Version) ? "" : " ")}{version.Version}",
|
||||
Y = (double?)(version.Count / linuxCount)
|
||||
Y = (double?) (version.Count / linuxCount)
|
||||
});
|
||||
|
||||
ViewData["linuxPieData"] = linuxPieData;
|
||||
|
||||
List<PieSeriesData> macosPieData = new List<PieSeriesData>();
|
||||
var macosPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal macosCount = ctx.OperatingSystems.Where(o => o.Name == PlatformID.MacOSX.ToString())
|
||||
.Sum(o => o.Count);
|
||||
foreach(OperatingSystem version in
|
||||
.Sum(o => o.Count);
|
||||
foreach (var version in
|
||||
ctx.OperatingSystems.Where(o => o.Name == PlatformID.MacOSX.ToString()))
|
||||
macosPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name =
|
||||
$"{DetectOS.GetPlatformName(PlatformID.MacOSX, version.Version)}{(string.IsNullOrEmpty(version.Version) ? "" : " ")}{version.Version}",
|
||||
Y = (double?)(version.Count / macosCount)
|
||||
Y = (double?) (version.Count / macosCount)
|
||||
});
|
||||
|
||||
ViewData["macosPieData"] = macosPieData;
|
||||
|
||||
List<PieSeriesData> windowsPieData = new List<PieSeriesData>();
|
||||
var windowsPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal windowsCount = ctx.OperatingSystems.Where(o => o.Name == PlatformID.Win32NT.ToString())
|
||||
.Sum(o => o.Count);
|
||||
foreach(OperatingSystem version in
|
||||
.Sum(o => o.Count);
|
||||
foreach (var version in
|
||||
ctx.OperatingSystems.Where(o => o.Name == PlatformID.Win32NT.ToString()))
|
||||
windowsPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name =
|
||||
$"{DetectOS.GetPlatformName(PlatformID.Win32NT, version.Version)}{(string.IsNullOrEmpty(version.Version) ? "" : " ")}{version.Version}",
|
||||
Y = (double?)(version.Count / windowsCount)
|
||||
Y = (double?) (version.Count / windowsCount)
|
||||
});
|
||||
|
||||
ViewData["windowsPieData"] = windowsPieData;
|
||||
}
|
||||
|
||||
if(ctx.Versions.Any())
|
||||
if (ctx.Versions.Any())
|
||||
{
|
||||
versions = new List<NameValueStats>();
|
||||
foreach(Version nvs in ctx.Versions)
|
||||
foreach (var nvs in ctx.Versions)
|
||||
versions.Add(new NameValueStats
|
||||
{
|
||||
name = nvs.Value == "previous" ? "Previous than 3.4.99.0" : nvs.Value,
|
||||
name = nvs.Value == "previous" ? "Previous than 3.4.99.0" : nvs.Value,
|
||||
Value = nvs.Count
|
||||
});
|
||||
|
||||
@@ -202,210 +200,211 @@ namespace DiscImageChef.Server.Controllers
|
||||
version.Value == "previous"
|
||||
? "Previous than 3.4.99.0"
|
||||
: version.Value,
|
||||
Y = (double?)(version.Count /
|
||||
totalVersionCount),
|
||||
Sliced = version.Value == "previous",
|
||||
Y = (double?) (version.Count /
|
||||
totalVersionCount),
|
||||
Sliced = version.Value == "previous",
|
||||
Selected = version.Value == "previous"
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
if(ctx.Commands.Any())
|
||||
if (ctx.Commands.Any())
|
||||
{
|
||||
ViewBag.repCommands = ctx.Commands.OrderBy(c => c.Name).ToList();
|
||||
|
||||
decimal totalCommandCount = ctx.Commands.Sum(o => o.Count);
|
||||
|
||||
ViewData["commandsPieData"] = ctx
|
||||
.Commands.Select(command => new PieSeriesData
|
||||
{
|
||||
Name = command.Name,
|
||||
Y = (double?)(command.Count /
|
||||
totalCommandCount),
|
||||
Sliced = command.Name == "analyze",
|
||||
Selected = command.Name == "analyze"
|
||||
}).ToList();
|
||||
.Commands.Select(command => new PieSeriesData
|
||||
{
|
||||
Name = command.Name,
|
||||
Y = (double?) (command.Count /
|
||||
totalCommandCount),
|
||||
Sliced = command.Name == "analyze",
|
||||
Selected = command.Name == "analyze"
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
if(ctx.Filters.Any())
|
||||
if (ctx.Filters.Any())
|
||||
{
|
||||
ViewBag.repFilters = ctx.Filters.OrderBy(filter => filter.Name).ToList();
|
||||
|
||||
List<PieSeriesData> filtersPieData = new List<PieSeriesData>();
|
||||
var filtersPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal totalFiltersCount = ctx.Filters.Sum(o => o.Count);
|
||||
foreach(Filter filter in ctx.Filters.ToList())
|
||||
foreach (var filter in ctx.Filters.ToList())
|
||||
filtersPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = filter.Name,
|
||||
Y = (double?)(filter.Count / totalFiltersCount),
|
||||
Sliced = filter.Name == "No filter",
|
||||
Name = filter.Name,
|
||||
Y = (double?) (filter.Count / totalFiltersCount),
|
||||
Sliced = filter.Name == "No filter",
|
||||
Selected = filter.Name == "No filter"
|
||||
});
|
||||
|
||||
ViewData["filtersPieData"] = filtersPieData;
|
||||
}
|
||||
|
||||
if(ctx.MediaFormats.Any())
|
||||
if (ctx.MediaFormats.Any())
|
||||
{
|
||||
ViewBag.repMediaImages = ctx.MediaFormats.OrderBy(filter => filter.Name).ToList();
|
||||
|
||||
List<PieSeriesData> formatsPieData = new List<PieSeriesData>();
|
||||
var formatsPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal totalFormatsCount = ctx.MediaFormats.Sum(o => o.Count);
|
||||
decimal top10FormatCount = 0;
|
||||
decimal top10FormatCount = 0;
|
||||
|
||||
foreach(MediaFormat format in ctx.MediaFormats.OrderByDescending(o => o.Count).Take(10))
|
||||
foreach (var format in ctx.MediaFormats.OrderByDescending(o => o.Count).Take(10))
|
||||
{
|
||||
top10FormatCount += format.Count;
|
||||
|
||||
formatsPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = format.Name, Y = (double?)(format.Count / totalFormatsCount)
|
||||
Name = format.Name, Y = (double?) (format.Count / totalFormatsCount)
|
||||
});
|
||||
}
|
||||
|
||||
formatsPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = "Other",
|
||||
Y = (double?)((totalFormatsCount - top10FormatCount) /
|
||||
totalFormatsCount),
|
||||
Sliced = true,
|
||||
Y = (double?) ((totalFormatsCount - top10FormatCount) /
|
||||
totalFormatsCount),
|
||||
Sliced = true,
|
||||
Selected = true
|
||||
});
|
||||
|
||||
ViewData["formatsPieData"] = formatsPieData;
|
||||
}
|
||||
|
||||
if(ctx.Partitions.Any())
|
||||
if (ctx.Partitions.Any())
|
||||
{
|
||||
ViewBag.repPartitions = ctx.Partitions.OrderBy(filter => filter.Name).ToList();
|
||||
|
||||
List<PieSeriesData> partitionsPieData = new List<PieSeriesData>();
|
||||
var partitionsPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal totalPartitionsCount = ctx.Partitions.Sum(o => o.Count);
|
||||
decimal top10PartitionCount = 0;
|
||||
decimal top10PartitionCount = 0;
|
||||
|
||||
foreach(Partition partition in ctx.Partitions.OrderByDescending(o => o.Count).Take(10))
|
||||
foreach (var partition in ctx.Partitions.OrderByDescending(o => o.Count).Take(10))
|
||||
{
|
||||
top10PartitionCount += partition.Count;
|
||||
|
||||
partitionsPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = partition.Name,
|
||||
Y = (double?)(partition.Count / totalPartitionsCount)
|
||||
Y = (double?) (partition.Count / totalPartitionsCount)
|
||||
});
|
||||
}
|
||||
|
||||
partitionsPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = "Other",
|
||||
Y = (double?)((totalPartitionsCount - top10PartitionCount) /
|
||||
totalPartitionsCount),
|
||||
Sliced = true,
|
||||
Y = (double?) ((totalPartitionsCount - top10PartitionCount) /
|
||||
totalPartitionsCount),
|
||||
Sliced = true,
|
||||
Selected = true
|
||||
});
|
||||
|
||||
ViewData["partitionsPieData"] = partitionsPieData;
|
||||
}
|
||||
|
||||
if(ctx.Filesystems.Any())
|
||||
if (ctx.Filesystems.Any())
|
||||
{
|
||||
ViewBag.repFilesystems = ctx.Filesystems.OrderBy(filter => filter.Name).ToList();
|
||||
|
||||
List<PieSeriesData> filesystemsPieData = new List<PieSeriesData>();
|
||||
var filesystemsPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal totalFilesystemsCount = ctx.Filesystems.Sum(o => o.Count);
|
||||
decimal top10FilesystemCount = 0;
|
||||
decimal top10FilesystemCount = 0;
|
||||
|
||||
foreach(Filesystem filesystem in ctx.Filesystems.OrderByDescending(o => o.Count).Take(10))
|
||||
foreach (var filesystem in ctx.Filesystems.OrderByDescending(o => o.Count).Take(10))
|
||||
{
|
||||
top10FilesystemCount += filesystem.Count;
|
||||
|
||||
filesystemsPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = filesystem.Name,
|
||||
Y = (double?)(filesystem.Count / totalFilesystemsCount)
|
||||
Y = (double?) (filesystem.Count / totalFilesystemsCount)
|
||||
});
|
||||
}
|
||||
|
||||
filesystemsPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = "Other",
|
||||
Y = (double?)((totalFilesystemsCount - top10FilesystemCount) /
|
||||
totalFilesystemsCount),
|
||||
Sliced = true,
|
||||
Y = (double?) ((totalFilesystemsCount - top10FilesystemCount) /
|
||||
totalFilesystemsCount),
|
||||
Sliced = true,
|
||||
Selected = true
|
||||
});
|
||||
|
||||
ViewData["filesystemsPieData"] = filesystemsPieData;
|
||||
}
|
||||
|
||||
if(ctx.Medias.Any())
|
||||
if (ctx.Medias.Any())
|
||||
{
|
||||
realMedia = new List<MediaItem>();
|
||||
realMedia = new List<MediaItem>();
|
||||
virtualMedia = new List<MediaItem>();
|
||||
foreach(Media nvs in ctx.Medias)
|
||||
foreach (var nvs in ctx.Medias)
|
||||
try
|
||||
{
|
||||
MediaType
|
||||
.MediaTypeToString((CommonTypes.MediaType)Enum.Parse(typeof(CommonTypes.MediaType), nvs.Type),
|
||||
out string type, out string subtype);
|
||||
.MediaTypeToString(
|
||||
(CommonTypes.MediaType) Enum.Parse(typeof(CommonTypes.MediaType), nvs.Type),
|
||||
out var type, out var subtype);
|
||||
|
||||
if(nvs.Real)
|
||||
realMedia.Add(new MediaItem {Type = type, SubType = subtype, Count = nvs.Count});
|
||||
if (nvs.Real)
|
||||
realMedia.Add(new MediaItem {Type = type, SubType = subtype, Count = nvs.Count});
|
||||
else virtualMedia.Add(new MediaItem {Type = type, SubType = subtype, Count = nvs.Count});
|
||||
}
|
||||
catch
|
||||
{
|
||||
if(nvs.Real)
|
||||
realMedia.Add(new MediaItem {Type = nvs.Type, SubType = null, Count = nvs.Count});
|
||||
if (nvs.Real)
|
||||
realMedia.Add(new MediaItem {Type = nvs.Type, SubType = null, Count = nvs.Count});
|
||||
else virtualMedia.Add(new MediaItem {Type = nvs.Type, SubType = null, Count = nvs.Count});
|
||||
}
|
||||
|
||||
if(realMedia.Count > 0)
|
||||
if (realMedia.Count > 0)
|
||||
{
|
||||
ViewBag.repRealMedia =
|
||||
realMedia.OrderBy(media => media.Type).ThenBy(media => media.SubType).ToList();
|
||||
|
||||
List<PieSeriesData> realMediaPieData = new List<PieSeriesData>();
|
||||
var realMediaPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal totalRealMediaCount = realMedia.Sum(o => o.Count);
|
||||
decimal top10RealMediaCount = 0;
|
||||
|
||||
foreach(MediaItem realMediaItem in realMedia.OrderByDescending(o => o.Count).Take(10))
|
||||
foreach (var realMediaItem in realMedia.OrderByDescending(o => o.Count).Take(10))
|
||||
{
|
||||
top10RealMediaCount += realMediaItem.Count;
|
||||
|
||||
realMediaPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = $"{realMediaItem.Type} ({realMediaItem.SubType})",
|
||||
Y = (double?)(realMediaItem.Count / totalRealMediaCount)
|
||||
Y = (double?) (realMediaItem.Count / totalRealMediaCount)
|
||||
});
|
||||
}
|
||||
|
||||
realMediaPieData.Add(new PieSeriesData
|
||||
{
|
||||
Name = "Other",
|
||||
Y = (double?)((totalRealMediaCount - top10RealMediaCount) /
|
||||
totalRealMediaCount),
|
||||
Sliced = true,
|
||||
Y = (double?) ((totalRealMediaCount - top10RealMediaCount) /
|
||||
totalRealMediaCount),
|
||||
Sliced = true,
|
||||
Selected = true
|
||||
});
|
||||
|
||||
ViewData["realMediaPieData"] = realMediaPieData;
|
||||
}
|
||||
|
||||
if(virtualMedia.Count > 0)
|
||||
if (virtualMedia.Count > 0)
|
||||
{
|
||||
ViewBag.repVirtualMedia =
|
||||
virtualMedia.OrderBy(media => media.Type).ThenBy(media => media.SubType).ToList();
|
||||
|
||||
List<PieSeriesData> virtualMediaPieData = new List<PieSeriesData>();
|
||||
var virtualMediaPieData = new List<PieSeriesData>();
|
||||
|
||||
decimal totalVirtualMediaCount = virtualMedia.Sum(o => o.Count);
|
||||
decimal top10VirtualMediaCount = 0;
|
||||
|
||||
foreach(MediaItem virtualMediaItem in virtualMedia.OrderByDescending(o => o.Count).Take(10))
|
||||
foreach (var virtualMediaItem in virtualMedia.OrderByDescending(o => o.Count).Take(10))
|
||||
{
|
||||
top10VirtualMediaCount += virtualMediaItem.Count;
|
||||
|
||||
@@ -413,8 +412,8 @@ namespace DiscImageChef.Server.Controllers
|
||||
{
|
||||
Name =
|
||||
$"{virtualMediaItem.Type} ({virtualMediaItem.SubType})",
|
||||
Y = (double?)(virtualMediaItem.Count /
|
||||
totalVirtualMediaCount)
|
||||
Y = (double?) (virtualMediaItem.Count /
|
||||
totalVirtualMediaCount)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -424,7 +423,7 @@ namespace DiscImageChef.Server.Controllers
|
||||
Y = (double?)
|
||||
((totalVirtualMediaCount - top10VirtualMediaCount) /
|
||||
totalVirtualMediaCount),
|
||||
Sliced = true,
|
||||
Sliced = true,
|
||||
Selected = true
|
||||
});
|
||||
|
||||
@@ -432,93 +431,100 @@ namespace DiscImageChef.Server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
if(ctx.DeviceStats.Any())
|
||||
if (ctx.DeviceStats.Any())
|
||||
{
|
||||
devices = new List<DeviceItem>();
|
||||
foreach(DeviceStat device in ctx.DeviceStats.ToList())
|
||||
foreach (var device in ctx.DeviceStats.ToList())
|
||||
{
|
||||
string xmlFile;
|
||||
if(!string.IsNullOrWhiteSpace(device.Manufacturer) &&
|
||||
!string.IsNullOrWhiteSpace(device.Model) &&
|
||||
!string.IsNullOrWhiteSpace(device.Revision))
|
||||
if (!string.IsNullOrWhiteSpace(device.Manufacturer) &&
|
||||
!string.IsNullOrWhiteSpace(device.Model) &&
|
||||
!string.IsNullOrWhiteSpace(device.Revision))
|
||||
xmlFile = device.Manufacturer + "_" + device.Model + "_" + device.Revision + ".xml";
|
||||
else if(!string.IsNullOrWhiteSpace(device.Manufacturer) &&
|
||||
!string.IsNullOrWhiteSpace(device.Model))
|
||||
else if (!string.IsNullOrWhiteSpace(device.Manufacturer) &&
|
||||
!string.IsNullOrWhiteSpace(device.Model))
|
||||
xmlFile = device.Manufacturer + "_" + device.Model + ".xml";
|
||||
else if(!string.IsNullOrWhiteSpace(device.Model) && !string.IsNullOrWhiteSpace(device.Revision))
|
||||
xmlFile = device.Model + "_" + device.Revision + ".xml";
|
||||
else xmlFile = device.Model + ".xml";
|
||||
else if (!string.IsNullOrWhiteSpace(device.Model) &&
|
||||
!string.IsNullOrWhiteSpace(device.Revision))
|
||||
xmlFile = device.Model + "_" + device.Revision + ".xml";
|
||||
else xmlFile = device.Model + ".xml";
|
||||
|
||||
xmlFile = xmlFile.Replace('/', '_').Replace('\\', '_').Replace('?', '_');
|
||||
|
||||
if(System.IO.File.Exists(Path.Combine(_environment.ContentRootPath, "Reports", xmlFile)))
|
||||
if (System.IO.File.Exists(Path.Combine(_environment.ContentRootPath, "Reports", xmlFile)))
|
||||
{
|
||||
DeviceReport deviceReport = new DeviceReport();
|
||||
var deviceReport = new DeviceReport();
|
||||
|
||||
XmlSerializer xs = new XmlSerializer(deviceReport.GetType());
|
||||
FileStream fs =
|
||||
WaitForFile(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(), "Reports", xmlFile),
|
||||
FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
deviceReport = (DeviceReport)xs.Deserialize(fs);
|
||||
var xs = new XmlSerializer(deviceReport.GetType());
|
||||
var fs =
|
||||
WaitForFile(
|
||||
Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Reports", xmlFile),
|
||||
FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
deviceReport = (DeviceReport) xs.Deserialize(fs);
|
||||
fs.Close();
|
||||
|
||||
DeviceReportV2 deviceReportV2 = new DeviceReportV2(deviceReport);
|
||||
var deviceReportV2 = new DeviceReportV2(deviceReport);
|
||||
|
||||
device.Report = ctx.Devices.Add(new Device(deviceReportV2)).Entity;
|
||||
ctx.SaveChanges();
|
||||
|
||||
System.IO.File
|
||||
.Delete(Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Reports", xmlFile));
|
||||
.Delete(Path.Combine(
|
||||
_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"Reports", xmlFile));
|
||||
}
|
||||
|
||||
devices.Add(new DeviceItem
|
||||
{
|
||||
Manufacturer = device.Manufacturer,
|
||||
Model = device.Model,
|
||||
Revision = device.Revision,
|
||||
Bus = device.Bus,
|
||||
Model = device.Model,
|
||||
Revision = device.Revision,
|
||||
Bus = device.Bus,
|
||||
ReportId = device.Report != null && device.Report.Id != 0
|
||||
? device.Report.Id
|
||||
: 0
|
||||
? device.Report.Id
|
||||
: 0
|
||||
});
|
||||
}
|
||||
|
||||
ViewBag.repDevices = devices.OrderBy(device => device.Manufacturer).ThenBy(device => device.Model)
|
||||
.ThenBy(device => device.Revision).ThenBy(device => device.Bus)
|
||||
.ToList();
|
||||
.ThenBy(device => device.Revision).ThenBy(device => device.Bus)
|
||||
.ToList();
|
||||
|
||||
ViewData["devicesBusPieData"] = (from deviceBus in devices.Select(d => d.Bus).Distinct()
|
||||
let deviceBusCount = devices.Count(d => d.Bus == deviceBus)
|
||||
select new PieSeriesData
|
||||
{
|
||||
Name = deviceBus,
|
||||
Y = deviceBusCount / (double)devices.Count
|
||||
}).ToList();
|
||||
let deviceBusCount = devices.Count(d => d.Bus == deviceBus)
|
||||
select new PieSeriesData
|
||||
{
|
||||
Name = deviceBus,
|
||||
Y = deviceBusCount / (double) devices.Count
|
||||
}).ToList();
|
||||
|
||||
ViewData["devicesManufacturerPieData"] =
|
||||
(from manufacturer in
|
||||
devices.Where(d => d.Manufacturer != null).Select(d => d.Manufacturer.ToLowerInvariant())
|
||||
devices.Where(d => d.Manufacturer != null)
|
||||
.Select(d => d.Manufacturer.ToLowerInvariant())
|
||||
.Distinct()
|
||||
let manufacturerCount = devices.Count(d => d.Manufacturer?.ToLowerInvariant() == manufacturer)
|
||||
select new PieSeriesData {Name = manufacturer, Y = manufacturerCount / (double)devices.Count})
|
||||
.ToList();
|
||||
let manufacturerCount =
|
||||
devices.Count(d => d.Manufacturer?.ToLowerInvariant() == manufacturer)
|
||||
select new PieSeriesData
|
||||
{Name = manufacturer, Y = manufacturerCount / (double) devices.Count})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
catch(Exception)
|
||||
catch (Exception)
|
||||
{
|
||||
#if DEBUG
|
||||
#if DEBUG
|
||||
throw;
|
||||
#endif
|
||||
#endif
|
||||
return Content("Could not read statistics");
|
||||
}
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
static FileStream WaitForFile(string fullPath, FileMode mode, FileAccess access, FileShare share)
|
||||
private static FileStream WaitForFile(string fullPath, FileMode mode, FileAccess access, FileShare share)
|
||||
{
|
||||
for(int numTries = 0; numTries < 100; numTries++)
|
||||
for (var numTries = 0; numTries < 100; numTries++)
|
||||
{
|
||||
FileStream fs = null;
|
||||
try
|
||||
@@ -526,7 +532,7 @@ namespace DiscImageChef.Server.Controllers
|
||||
fs = new FileStream(fullPath, mode, access, share);
|
||||
return fs;
|
||||
}
|
||||
catch(IOException)
|
||||
catch (IOException)
|
||||
{
|
||||
fs?.Dispose();
|
||||
Thread.Sleep(50);
|
||||
|
||||
@@ -30,13 +30,10 @@
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes.Metadata;
|
||||
using DiscImageChef.Dto;
|
||||
using DiscImageChef.Server.Models;
|
||||
@@ -48,7 +45,7 @@ namespace DiscImageChef.Server.Controllers
|
||||
{
|
||||
public class UpdateController : Controller
|
||||
{
|
||||
private DicServerContext _ctx;
|
||||
private readonly DicServerContext _ctx;
|
||||
|
||||
public UpdateController(DicServerContext ctx)
|
||||
{
|
||||
@@ -63,40 +60,43 @@ namespace DiscImageChef.Server.Controllers
|
||||
[HttpGet]
|
||||
public ActionResult Update(long timestamp)
|
||||
{
|
||||
SyncDto sync = new SyncDto();
|
||||
DateTime lastSync = DateHandlers.UnixToDateTime(timestamp);
|
||||
var sync = new SyncDto();
|
||||
var lastSync = DateHandlers.UnixToDateTime(timestamp);
|
||||
|
||||
sync.UsbVendors = new List<UsbVendorDto>();
|
||||
foreach(UsbVendor vendor in _ctx.UsbVendors.Where(v => v.ModifiedWhen > lastSync))
|
||||
sync.UsbVendors.Add(new UsbVendorDto {VendorId = (ushort)vendor.VendorId, Vendor = vendor.Vendor});
|
||||
foreach (var vendor in _ctx.UsbVendors.Where(v => v.ModifiedWhen > lastSync))
|
||||
sync.UsbVendors.Add(new UsbVendorDto {VendorId = (ushort) vendor.VendorId, Vendor = vendor.Vendor});
|
||||
|
||||
sync.UsbProducts = new List<UsbProductDto>();
|
||||
foreach(UsbProduct product in _ctx.UsbProducts.Include(p => p.Vendor).Where(p => p.ModifiedWhen > lastSync))
|
||||
foreach (var product in _ctx.UsbProducts.Include(p => p.Vendor).Where(p => p.ModifiedWhen > lastSync))
|
||||
sync.UsbProducts.Add(new UsbProductDto
|
||||
{
|
||||
Id = product.Id,
|
||||
Product = product.Product,
|
||||
ProductId = (ushort)product.ProductId,
|
||||
VendorId = (ushort)product.Vendor.VendorId
|
||||
Id = product.Id,
|
||||
Product = product.Product,
|
||||
ProductId = (ushort) product.ProductId,
|
||||
VendorId = (ushort) product.Vendor.VendorId
|
||||
});
|
||||
|
||||
sync.Offsets = new List<CdOffsetDto>();
|
||||
foreach(CompactDiscOffset offset in _ctx.CdOffsets.Where(o => o.ModifiedWhen > lastSync))
|
||||
foreach (var offset in _ctx.CdOffsets.Where(o => o.ModifiedWhen > lastSync))
|
||||
sync.Offsets.Add(new CdOffsetDto(offset, offset.Id));
|
||||
|
||||
sync.Devices = new List<DeviceDto>();
|
||||
foreach(Device device in _ctx.Devices.Where(d => d.ModifiedWhen > lastSync).ToList())
|
||||
foreach (var device in _ctx.Devices.Where(d => d.ModifiedWhen > lastSync).ToList())
|
||||
sync.Devices.Add(new
|
||||
DeviceDto(JsonConvert.DeserializeObject<DeviceReportV2>(JsonConvert.SerializeObject(device, Formatting.None, new JsonSerializerSettings {ReferenceLoopHandling = ReferenceLoopHandling.Ignore})),
|
||||
device.Id, device.OptimalMultipleSectorsRead));
|
||||
DeviceDto(
|
||||
JsonConvert.DeserializeObject<DeviceReportV2>(JsonConvert.SerializeObject(device,
|
||||
Formatting.None,
|
||||
new JsonSerializerSettings {ReferenceLoopHandling = ReferenceLoopHandling.Ignore})),
|
||||
device.Id, device.OptimalMultipleSectorsRead));
|
||||
|
||||
JsonSerializer js = JsonSerializer.Create();
|
||||
StringWriter sw = new StringWriter();
|
||||
var js = JsonSerializer.Create();
|
||||
var sw = new StringWriter();
|
||||
js.Serialize(sw, sync);
|
||||
|
||||
return new ContentResult
|
||||
{
|
||||
StatusCode = (int)HttpStatusCode.OK,
|
||||
StatusCode = (int) HttpStatusCode.OK,
|
||||
Content = sw.ToString(),
|
||||
ContentType = "application/json"
|
||||
};
|
||||
|
||||
@@ -34,19 +34,15 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Xml.Serialization;
|
||||
using Cinchoo.PGP;
|
||||
using DiscImageChef.CommonTypes.Metadata;
|
||||
using DiscImageChef.Server.Models;
|
||||
using MailKit.Net.Smtp;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Hosting.Internal;
|
||||
using MimeKit;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -54,8 +50,8 @@ namespace DiscImageChef.Server.Controllers
|
||||
{
|
||||
public class UploadReportController : Controller
|
||||
{
|
||||
private DicServerContext ctx;
|
||||
private IWebHostEnvironment _environment;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly DicServerContext ctx;
|
||||
|
||||
public UploadReportController(IWebHostEnvironment environment, DicServerContext _ctx)
|
||||
{
|
||||
@@ -71,53 +67,54 @@ namespace DiscImageChef.Server.Controllers
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UploadReport()
|
||||
{
|
||||
ContentResult response = new ContentResult {StatusCode = (int)HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
var response = new ContentResult {StatusCode = (int) HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
|
||||
try
|
||||
{
|
||||
DeviceReport newReport = new DeviceReport();
|
||||
HttpRequest request = HttpContext.Request;
|
||||
var newReport = new DeviceReport();
|
||||
var request = HttpContext.Request;
|
||||
|
||||
XmlSerializer xs = new XmlSerializer(newReport.GetType());
|
||||
newReport = (DeviceReport) xs.Deserialize(new StringReader(await new StreamReader(request.Body).ReadToEndAsync()));
|
||||
var xs = new XmlSerializer(newReport.GetType());
|
||||
newReport = (DeviceReport) xs.Deserialize(
|
||||
new StringReader(await new StreamReader(request.Body).ReadToEndAsync()));
|
||||
|
||||
if(newReport == null)
|
||||
if (newReport == null)
|
||||
{
|
||||
response.Content = "notstats";
|
||||
return response;
|
||||
}
|
||||
|
||||
DeviceReportV2 reportV2 = new DeviceReportV2(newReport);
|
||||
StringWriter jsonSw = new StringWriter();
|
||||
var reportV2 = new DeviceReportV2(newReport);
|
||||
var jsonSw = new StringWriter();
|
||||
jsonSw.Write(JsonConvert.SerializeObject(reportV2, Formatting.Indented,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}));
|
||||
string reportV2String = jsonSw.ToString();
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}));
|
||||
var reportV2String = jsonSw.ToString();
|
||||
jsonSw.Close();
|
||||
|
||||
ctx.Reports.Add(new UploadedReport(reportV2));
|
||||
ctx.SaveChanges();
|
||||
|
||||
MemoryStream pgpIn = new MemoryStream(Encoding.UTF8.GetBytes(reportV2String));
|
||||
MemoryStream pgpOut = new MemoryStream();
|
||||
ChoPGPEncryptDecrypt pgp = new ChoPGPEncryptDecrypt();
|
||||
var pgpIn = new MemoryStream(Encoding.UTF8.GetBytes(reportV2String));
|
||||
var pgpOut = new MemoryStream();
|
||||
var pgp = new ChoPGPEncryptDecrypt();
|
||||
pgp.Encrypt(pgpIn, pgpOut,
|
||||
Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"public.asc"), true);
|
||||
Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"public.asc"));
|
||||
pgpOut.Position = 0;
|
||||
reportV2String = Encoding.UTF8.GetString(pgpOut.ToArray());
|
||||
reportV2String = Encoding.UTF8.GetString(pgpOut.ToArray());
|
||||
|
||||
MimeMessage message = new MimeMessage
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Subject = "New device report (old version)",
|
||||
Body = new TextPart("plain") {Text = reportV2String}
|
||||
Body = new TextPart("plain") {Text = reportV2String}
|
||||
};
|
||||
message.From.Add(new MailboxAddress("DiscImageChef", "dic@claunia.com"));
|
||||
message.From.Add(new MailboxAddress("DiscImageChef", "dic@claunia.com"));
|
||||
message.To.Add(new MailboxAddress("Natalia Portillo", "claunia@claunia.com"));
|
||||
|
||||
using(SmtpClient client = new SmtpClient())
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Connect("mail.claunia.com", 25, false);
|
||||
client.Send(message);
|
||||
@@ -130,9 +127,9 @@ namespace DiscImageChef.Server.Controllers
|
||||
// ReSharper disable once RedundantCatchClause
|
||||
catch
|
||||
{
|
||||
#if DEBUG
|
||||
if(Debugger.IsAttached) throw;
|
||||
#endif
|
||||
#if DEBUG
|
||||
if (Debugger.IsAttached) throw;
|
||||
#endif
|
||||
response.Content = "error";
|
||||
return response;
|
||||
}
|
||||
@@ -146,17 +143,17 @@ namespace DiscImageChef.Server.Controllers
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UploadReportV2()
|
||||
{
|
||||
ContentResult response = new ContentResult {StatusCode = (int)HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
var response = new ContentResult {StatusCode = (int) HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
|
||||
try
|
||||
{
|
||||
HttpRequest request = HttpContext.Request;
|
||||
var request = HttpContext.Request;
|
||||
|
||||
StreamReader sr = new StreamReader(request.Body);
|
||||
string reportJson = await sr.ReadToEndAsync();
|
||||
DeviceReportV2 newReport = JsonConvert.DeserializeObject<DeviceReportV2>(reportJson);
|
||||
var sr = new StreamReader(request.Body);
|
||||
var reportJson = await sr.ReadToEndAsync();
|
||||
var newReport = JsonConvert.DeserializeObject<DeviceReportV2>(reportJson);
|
||||
|
||||
if(newReport == null)
|
||||
if (newReport == null)
|
||||
{
|
||||
response.Content = "notstats";
|
||||
return response;
|
||||
@@ -165,23 +162,23 @@ namespace DiscImageChef.Server.Controllers
|
||||
ctx.Reports.Add(new UploadedReport(newReport));
|
||||
ctx.SaveChanges();
|
||||
|
||||
MemoryStream pgpIn = new MemoryStream(Encoding.UTF8.GetBytes(reportJson));
|
||||
MemoryStream pgpOut = new MemoryStream();
|
||||
ChoPGPEncryptDecrypt pgp = new ChoPGPEncryptDecrypt();
|
||||
var pgpIn = new MemoryStream(Encoding.UTF8.GetBytes(reportJson));
|
||||
var pgpOut = new MemoryStream();
|
||||
var pgp = new ChoPGPEncryptDecrypt();
|
||||
pgp.Encrypt(pgpIn, pgpOut,
|
||||
Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"public.asc"), true);
|
||||
Path.Combine(_environment.ContentRootPath ?? throw new InvalidOperationException(),
|
||||
"public.asc"));
|
||||
pgpOut.Position = 0;
|
||||
reportJson = Encoding.UTF8.GetString(pgpOut.ToArray());
|
||||
reportJson = Encoding.UTF8.GetString(pgpOut.ToArray());
|
||||
|
||||
MimeMessage message = new MimeMessage
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Subject = "New device report", Body = new TextPart("plain") {Text = reportJson}
|
||||
};
|
||||
message.From.Add(new MailboxAddress("DiscImageChef", "dic@claunia.com"));
|
||||
message.From.Add(new MailboxAddress("DiscImageChef", "dic@claunia.com"));
|
||||
message.To.Add(new MailboxAddress("Natalia Portillo", "claunia@claunia.com"));
|
||||
|
||||
using(SmtpClient client = new SmtpClient())
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Connect("mail.claunia.com", 25, false);
|
||||
client.Send(message);
|
||||
@@ -194,10 +191,10 @@ namespace DiscImageChef.Server.Controllers
|
||||
// ReSharper disable once RedundantCatchClause
|
||||
catch
|
||||
{
|
||||
#if DEBUG
|
||||
if(Debugger.IsAttached) throw;
|
||||
#endif
|
||||
response.Content ="error";
|
||||
#if DEBUG
|
||||
if (Debugger.IsAttached) throw;
|
||||
#endif
|
||||
response.Content = "error";
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,16 +35,12 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Xml.Serialization;
|
||||
using DiscImageChef.CommonTypes.Metadata;
|
||||
using DiscImageChef.Server.Models;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using OperatingSystem = DiscImageChef.Server.Models.OperatingSystem;
|
||||
@@ -54,7 +50,7 @@ namespace DiscImageChef.Server.Controllers
|
||||
{
|
||||
public class UploadStatsController : Controller
|
||||
{
|
||||
DicServerContext _ctx;
|
||||
private readonly DicServerContext _ctx;
|
||||
private IWebHostEnvironment _environment;
|
||||
|
||||
public UploadStatsController(IWebHostEnvironment environment, DicServerContext ctx)
|
||||
@@ -62,6 +58,7 @@ namespace DiscImageChef.Server.Controllers
|
||||
_environment = environment;
|
||||
_ctx = ctx;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Receives statistics from DiscImageChef.Core, processes them and adds them to a server-side global statistics XML
|
||||
/// </summary>
|
||||
@@ -70,17 +67,18 @@ namespace DiscImageChef.Server.Controllers
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UploadStats()
|
||||
{
|
||||
ContentResult response = new ContentResult {StatusCode = (int)HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
var response = new ContentResult {StatusCode = (int) HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
|
||||
try
|
||||
{
|
||||
Stats newStats = new Stats();
|
||||
HttpRequest request = HttpContext.Request;
|
||||
var newStats = new Stats();
|
||||
var request = HttpContext.Request;
|
||||
|
||||
XmlSerializer xs = new XmlSerializer(newStats.GetType());
|
||||
newStats = (Stats) xs.Deserialize(new StringReader(await new StreamReader(request.Body).ReadToEndAsync()));
|
||||
var xs = new XmlSerializer(newStats.GetType());
|
||||
newStats = (Stats) xs.Deserialize(
|
||||
new StringReader(await new StreamReader(request.Body).ReadToEndAsync()));
|
||||
|
||||
if(newStats == null)
|
||||
if (newStats == null)
|
||||
{
|
||||
response.Content = "notstats";
|
||||
return response;
|
||||
@@ -91,11 +89,11 @@ namespace DiscImageChef.Server.Controllers
|
||||
response.Content = "ok";
|
||||
return response;
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
if(Debugger.IsAttached) throw;
|
||||
#endif
|
||||
#if DEBUG
|
||||
if (Debugger.IsAttached) throw;
|
||||
#endif
|
||||
response.Content = "error";
|
||||
return response;
|
||||
}
|
||||
@@ -109,119 +107,120 @@ namespace DiscImageChef.Server.Controllers
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UploadStatsV2()
|
||||
{
|
||||
ContentResult response = new ContentResult {StatusCode = (int)HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
var response = new ContentResult {StatusCode = (int) HttpStatusCode.OK, ContentType = "text/plain"};
|
||||
|
||||
try
|
||||
{
|
||||
HttpRequest request = HttpContext.Request;
|
||||
var request = HttpContext.Request;
|
||||
|
||||
StreamReader sr = new StreamReader(request.Body);
|
||||
var sr = new StreamReader(request.Body);
|
||||
var statsString = await sr.ReadToEndAsync();
|
||||
StatsDto newstats = JsonConvert.DeserializeObject<StatsDto>(statsString);
|
||||
var newstats = JsonConvert.DeserializeObject<StatsDto>(statsString);
|
||||
|
||||
if(newstats == null)
|
||||
if (newstats == null)
|
||||
{
|
||||
response.Content = "notstats";
|
||||
return response;
|
||||
}
|
||||
|
||||
if(newstats.Commands != null)
|
||||
foreach(NameValueStats nvs in newstats.Commands)
|
||||
if (newstats.Commands != null)
|
||||
foreach (var nvs in newstats.Commands)
|
||||
{
|
||||
Command existing = _ctx.Commands.FirstOrDefault(c => c.Name == nvs.name);
|
||||
var existing = _ctx.Commands.FirstOrDefault(c => c.Name == nvs.name);
|
||||
|
||||
if(existing == null) _ctx.Commands.Add(new Command {Name = nvs.name, Count = nvs.Value});
|
||||
if (existing == null) _ctx.Commands.Add(new Command {Name = nvs.name, Count = nvs.Value});
|
||||
else existing.Count += nvs.Value;
|
||||
}
|
||||
|
||||
if(newstats.Versions != null)
|
||||
foreach(NameValueStats nvs in newstats.Versions)
|
||||
if (newstats.Versions != null)
|
||||
foreach (var nvs in newstats.Versions)
|
||||
{
|
||||
Version existing = _ctx.Versions.FirstOrDefault(c => c.Value == nvs.name);
|
||||
var existing = _ctx.Versions.FirstOrDefault(c => c.Value == nvs.name);
|
||||
|
||||
if(existing == null) _ctx.Versions.Add(new Version {Value = nvs.name, Count = nvs.Value});
|
||||
if (existing == null) _ctx.Versions.Add(new Version {Value = nvs.name, Count = nvs.Value});
|
||||
else existing.Count += nvs.Value;
|
||||
}
|
||||
|
||||
if(newstats.Filesystems != null)
|
||||
foreach(NameValueStats nvs in newstats.Filesystems)
|
||||
if (newstats.Filesystems != null)
|
||||
foreach (var nvs in newstats.Filesystems)
|
||||
{
|
||||
Filesystem existing = _ctx.Filesystems.FirstOrDefault(c => c.Name == nvs.name);
|
||||
var existing = _ctx.Filesystems.FirstOrDefault(c => c.Name == nvs.name);
|
||||
|
||||
if(existing == null) _ctx.Filesystems.Add(new Filesystem {Name = nvs.name, Count = nvs.Value});
|
||||
if (existing == null) _ctx.Filesystems.Add(new Filesystem {Name = nvs.name, Count = nvs.Value});
|
||||
else existing.Count += nvs.Value;
|
||||
}
|
||||
|
||||
if(newstats.Partitions != null)
|
||||
foreach(NameValueStats nvs in newstats.Partitions)
|
||||
if (newstats.Partitions != null)
|
||||
foreach (var nvs in newstats.Partitions)
|
||||
{
|
||||
Partition existing = _ctx.Partitions.FirstOrDefault(c => c.Name == nvs.name);
|
||||
var existing = _ctx.Partitions.FirstOrDefault(c => c.Name == nvs.name);
|
||||
|
||||
if(existing == null) _ctx.Partitions.Add(new Partition {Name = nvs.name, Count = nvs.Value});
|
||||
if (existing == null) _ctx.Partitions.Add(new Partition {Name = nvs.name, Count = nvs.Value});
|
||||
else existing.Count += nvs.Value;
|
||||
}
|
||||
|
||||
if(newstats.MediaFormats != null)
|
||||
foreach(NameValueStats nvs in newstats.MediaFormats)
|
||||
if (newstats.MediaFormats != null)
|
||||
foreach (var nvs in newstats.MediaFormats)
|
||||
{
|
||||
MediaFormat existing = _ctx.MediaFormats.FirstOrDefault(c => c.Name == nvs.name);
|
||||
var existing = _ctx.MediaFormats.FirstOrDefault(c => c.Name == nvs.name);
|
||||
|
||||
if(existing == null) _ctx.MediaFormats.Add(new MediaFormat {Name = nvs.name, Count = nvs.Value});
|
||||
if (existing == null)
|
||||
_ctx.MediaFormats.Add(new MediaFormat {Name = nvs.name, Count = nvs.Value});
|
||||
else existing.Count += nvs.Value;
|
||||
}
|
||||
|
||||
if(newstats.Filters != null)
|
||||
foreach(NameValueStats nvs in newstats.Filters)
|
||||
if (newstats.Filters != null)
|
||||
foreach (var nvs in newstats.Filters)
|
||||
{
|
||||
Filter existing = _ctx.Filters.FirstOrDefault(c => c.Name == nvs.name);
|
||||
var existing = _ctx.Filters.FirstOrDefault(c => c.Name == nvs.name);
|
||||
|
||||
if(existing == null) _ctx.Filters.Add(new Filter {Name = nvs.name, Count = nvs.Value});
|
||||
if (existing == null) _ctx.Filters.Add(new Filter {Name = nvs.name, Count = nvs.Value});
|
||||
else existing.Count += nvs.Value;
|
||||
}
|
||||
|
||||
if(newstats.OperatingSystems != null)
|
||||
foreach(OsStats operatingSystem in newstats.OperatingSystems)
|
||||
if (newstats.OperatingSystems != null)
|
||||
foreach (var operatingSystem in newstats.OperatingSystems)
|
||||
{
|
||||
OperatingSystem existing =
|
||||
_ctx.OperatingSystems.FirstOrDefault(c => c.Name == operatingSystem.name &&
|
||||
c.Version == operatingSystem.version);
|
||||
var existing =
|
||||
_ctx.OperatingSystems.FirstOrDefault(c => c.Name == operatingSystem.name &&
|
||||
c.Version == operatingSystem.version);
|
||||
|
||||
if(existing == null)
|
||||
if (existing == null)
|
||||
_ctx.OperatingSystems.Add(new OperatingSystem
|
||||
{
|
||||
Name = operatingSystem.name,
|
||||
Name = operatingSystem.name,
|
||||
Version = operatingSystem.version,
|
||||
Count = operatingSystem.Value
|
||||
Count = operatingSystem.Value
|
||||
});
|
||||
else existing.Count += operatingSystem.Value;
|
||||
}
|
||||
|
||||
if(newstats.Medias != null)
|
||||
foreach(MediaStats media in newstats.Medias)
|
||||
if (newstats.Medias != null)
|
||||
foreach (var media in newstats.Medias)
|
||||
{
|
||||
Media existing = _ctx.Medias.FirstOrDefault(c => c.Type == media.type && c.Real == media.real);
|
||||
var existing = _ctx.Medias.FirstOrDefault(c => c.Type == media.type && c.Real == media.real);
|
||||
|
||||
if(existing == null)
|
||||
if (existing == null)
|
||||
_ctx.Medias.Add(new Media {Type = media.type, Real = media.real, Count = media.Value});
|
||||
else existing.Count += media.Value;
|
||||
}
|
||||
|
||||
if(newstats.Devices != null)
|
||||
foreach(DeviceStats device in newstats.Devices)
|
||||
if (newstats.Devices != null)
|
||||
foreach (var device in newstats.Devices)
|
||||
{
|
||||
DeviceStat existing =
|
||||
_ctx.DeviceStats.FirstOrDefault(c => c.Bus == device.Bus &&
|
||||
c.Manufacturer == device.Manufacturer &&
|
||||
c.Model == device.Model &&
|
||||
c.Revision == device.Revision);
|
||||
var existing =
|
||||
_ctx.DeviceStats.FirstOrDefault(c => c.Bus == device.Bus &&
|
||||
c.Manufacturer == device.Manufacturer &&
|
||||
c.Model == device.Model &&
|
||||
c.Revision == device.Revision);
|
||||
|
||||
if(existing == null)
|
||||
if (existing == null)
|
||||
_ctx.DeviceStats.Add(new DeviceStat
|
||||
{
|
||||
Bus = device.Bus,
|
||||
Bus = device.Bus,
|
||||
Manufacturer = device.Manufacturer,
|
||||
Model = device.Model,
|
||||
Revision = device.Revision
|
||||
Model = device.Model,
|
||||
Revision = device.Revision
|
||||
});
|
||||
}
|
||||
|
||||
@@ -233,17 +232,17 @@ namespace DiscImageChef.Server.Controllers
|
||||
// ReSharper disable once RedundantCatchClause
|
||||
catch
|
||||
{
|
||||
#if DEBUG
|
||||
if(Debugger.IsAttached) throw;
|
||||
#endif
|
||||
#if DEBUG
|
||||
if (Debugger.IsAttached) throw;
|
||||
#endif
|
||||
response.Content = "error";
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
FileStream WaitForFile(string fullPath, FileMode mode, FileAccess access, FileShare share)
|
||||
private FileStream WaitForFile(string fullPath, FileMode mode, FileAccess access, FileShare share)
|
||||
{
|
||||
for(int numTries = 0; numTries < 100; numTries++)
|
||||
for (var numTries = 0; numTries < 100; numTries++)
|
||||
{
|
||||
FileStream fs = null;
|
||||
try
|
||||
@@ -251,9 +250,9 @@ namespace DiscImageChef.Server.Controllers
|
||||
fs = new FileStream(fullPath, mode, access, share);
|
||||
return fs;
|
||||
}
|
||||
catch(IOException)
|
||||
catch (IOException)
|
||||
{
|
||||
if(fs != null) fs.Dispose();
|
||||
if (fs != null) fs.Dispose();
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user