Browse Source

Add project files.

VINNO 1 year ago
parent
commit
84d4e9ed4c

+ 25 - 0
StationProbe.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.34221.43
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StationProbe", "StationProbe\StationProbe.csproj", "{F2BEB2F3-17A5-4DE0-8FD5-FF5A576CC621}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F2BEB2F3-17A5-4DE0-8FD5-FF5A576CC621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F2BEB2F3-17A5-4DE0-8FD5-FF5A576CC621}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F2BEB2F3-17A5-4DE0-8FD5-FF5A576CC621}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F2BEB2F3-17A5-4DE0-8FD5-FF5A576CC621}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {4AAA2C8C-F3EB-4924-BC95-6A7B3C27C60E}
+	EndGlobalSection
+EndGlobal

+ 71 - 0
StationProbe/Database.cs

@@ -0,0 +1,71 @@
+using SQLite;
+
+namespace StationProbe
+{
+    internal class Database:IDisposable
+    {
+        private readonly SQLiteConnection _db;
+
+        public Database()
+        {
+            _db = new SQLiteConnection("d:\\database.db");
+            _db.CreateTable<Image>();
+            _db.CreateTable<Exam>();
+            _db.CreateTable<BatchTask>();
+        }
+
+
+        public void AddBatchTask(BatchTask batchTask)
+        {
+            _db.Insert(batchTask);
+        }
+
+
+        public void AddImage(Image image)
+        {
+            _db.Insert(image);
+        }
+
+        public void AddExam(Exam exam)
+        {
+            _db.Insert(exam);
+        }
+
+        public BatchTask[] GetBatchTasks()
+        {
+            return _db.Table<BatchTask>().ToArray();
+        }
+
+        public BatchTask? GetBatchTask(int id)
+        {
+            return _db.Table<BatchTask>().FirstOrDefault(x=>x.Id == id);
+        }
+
+        public void UpdateBatchTask(BatchTask batchTask)
+        {
+            _db.Update(batchTask);
+        }
+
+        public Exam[] GetExams(int batchTaskId, int page)
+        {
+            return _db.Table<Exam>().Where(x=>x.BatchTaskId == batchTaskId && x.PageIndex == page).OrderBy(x=>x.Id).ToArray();
+        }
+
+        public Image[] GetImages(int examId)
+        {
+            return _db.Table<Image>().Where(x => x.ExamId == examId).OrderBy(x=>x.ImageIndex).ToArray();
+        }
+
+        public Exam? GetLastExam(int batchTaskId)
+        {
+            return _db.Table<Exam>().Where(x => x.BatchTaskId == batchTaskId).OrderByDescending(x=>x.ExamIndex).FirstOrDefault();
+        }
+
+        public void Dispose()
+        {
+            _db?.Dispose();
+        }
+    }
+
+
+}

+ 73 - 0
StationProbe/Entities.cs

@@ -0,0 +1,73 @@
+using SQLite;
+
+namespace StationProbe
+{
+    [Table("Images")]
+    public class Image
+    {
+        [PrimaryKey]
+        public string Id { get; set; }
+
+        [Indexed]
+        public string ExamId { get; set; }
+
+        [Indexed]
+        public int ImageIndex { get; set; }
+
+        public byte[] Data { get; set; }
+
+        public DateTime CreateTime { get; set; }
+    }
+
+    [Table("BatchTasks")]
+    internal class BatchTask
+    {
+        [PrimaryKey, AutoIncrement]
+        public int Id { get; set; }
+
+        public string Name { get; set; }
+
+        public int PageCount { get; set; }
+
+        public int ExamCount { get; set; }
+
+        public DateTime Start { get; set; }
+
+        public DateTime End { get; set; }
+
+        public DateTime CreateTime { get; set; }
+    }
+
+
+    [Table("Exams")]
+    internal class Exam
+    {
+        [PrimaryKey]
+        public string Id { get; set; }
+
+        public string PatientName { get; set; }
+
+        public int PatientAge { get; set; }
+
+        public string PatientSex { get; set; }
+
+        public DateTime ExamDate { get; set; }
+
+        public string Report { get; set; }
+
+
+        [Indexed]
+        public int BatchTaskId { get; set; }
+
+        [Indexed]
+        public int ExamIndex { get; set; }
+
+        [Indexed]
+        public int PageIndex { get; set; }
+
+        [Indexed]
+        public int ExamIndexInPage { get; set; }
+
+        public DateTime CreateTime { get; set; }
+    }
+}

+ 71 - 0
StationProbe/Logger.cs

@@ -0,0 +1,71 @@
+namespace StationProbe
+{
+    internal class Logger
+    {
+        private static DateTime _date;
+
+        private static StreamWriter? _logWriter;
+
+        private static readonly object _logWriterLocker = new();
+
+        public static bool ConsoleOutput { get; set; } = true;
+
+        static Logger()
+        {
+            RebuildLogger();
+        }
+
+        private static void RebuildLogger()
+        {
+            var logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
+            if (!Directory.Exists(logDirectory))
+            {
+                Directory.CreateDirectory(logDirectory);
+            }
+            var today = DateTime.Today;
+            var logTag = $"{today:yyyyMMdd}";
+            var logFileName = $"log_{logTag}.log";
+            var logFile = Path.Combine(logDirectory, logFileName);
+            if (!File.Exists(logFile))
+            {
+                _logWriter?.Close();
+                var logFileStream = new FileStream(logFile, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
+                _logWriter = new StreamWriter(logFileStream);
+            }
+            else
+            {
+                _logWriter?.Close();
+                var logFileStream = new FileStream(logFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
+                logFileStream.Position = logFileStream.Length;
+                _logWriter = new StreamWriter(logFileStream);
+            }
+        }
+
+        public static void WriteLine(string log)
+        {
+            lock (_logWriterLocker)
+            {
+                if (DateTime.Today != _date)
+                {
+                    RebuildLogger();
+                    _date = DateTime.Today;
+                }
+                try
+                {
+                    var now = DateTime.Now;
+                    var message = $"[{now:HH:mm:ss},{now.Millisecond:d3}]-{log}";
+                    _logWriter?.WriteLine(message);
+                    _logWriter?.Flush();
+                    if (ConsoleOutput)
+                    {
+                        Console.WriteLine(message);
+                    }
+                }
+                catch (Exception)
+                {
+                    // There is exception during writing log, so just ignore
+                }
+            }
+        }
+    }
+}

+ 158 - 0
StationProbe/ProbeTask.cs

@@ -0,0 +1,158 @@
+using PuppeteerSharp;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace StationProbe
+{
+
+    internal class LoginTask
+    {
+        private readonly string _loginUrl;
+        public LoginTask(string loginUrl) 
+        {
+            _loginUrl = loginUrl;
+        }
+
+        public async Task<IPage> ExecuteAsync(IPage input, Database db)
+        {
+            await input.GoToAsync(_loginUrl);
+            //username
+            await input.WaitForSelectorAsync("input[_bl_13]");
+            await input.FocusAsync("input[_bl_13]");
+            await input.Keyboard.TypeAsync("justin.xing");
+            //password
+            await input.WaitForSelectorAsync("input[_bl_14]");
+            await input.FocusAsync("input[_bl_14]");
+            await input.Keyboard.TypeAsync("123456");
+            //login
+            var button = await input.WaitForSelectorAsync("button[_bl_15]");
+            await button.ClickAsync();
+
+            await input.WaitForNavigationAsync();
+            await input.WaitForNetworkIdleAsync();
+
+            return input;
+        }
+    }
+
+    internal class MenuTask
+    {
+        public async Task<IFrame> ExecuteAsync(IPage input, Database db)
+        {
+            var frame = await input.WaitForFrameAsync("");
+            return frame;
+        }
+    }
+
+    internal class FilterTask
+    {
+        private DateTime _start;
+        private DateTime _end;
+
+        public int PageCount { get; private set; }
+
+        public int ExamCount { get; private set; }
+
+        public FilterTask(DateTime start, DateTime end)
+        {
+            _start = start;
+            _end = end;
+        }
+
+        public async Task<IFrame> ExecuteAsync(IPage page, IFrame frame, Database db)
+        {
+            await frame.WaitForSelectorAsync("input[_bl_13]");
+            await frame.FocusAsync("input[_bl_13]");
+            await page.Keyboard.TypeAsync("justin.xing");
+            return frame;
+        }
+
+    }
+
+    internal class PageTask
+    {
+        private readonly int _page;
+        public PageTask(int page)
+        {
+            _page = page;
+        }
+
+        public async Task<IFrame> ExecuteAsync(IFrame input, Database db)
+        {
+           
+            return input;
+        }
+    }
+
+    internal class ExamTask
+    {
+        private readonly int _batchTaskId;
+        private readonly int _pageIndex;
+        private readonly int _examIndex;
+        private readonly int _examIndexInPage;
+
+        public ExamTask(int batchTaskId, int pageIndex, int examIndex, int examIndexInPage)
+        {
+            _batchTaskId = batchTaskId;
+            _pageIndex = pageIndex;
+            _examIndex = examIndex;
+            _examIndexInPage = examIndexInPage;
+        }
+
+        public async Task<IFrame> ExecuteAsync(IFrame input, Database db)
+        {
+            var exmaId = Guid.NewGuid().ToString("N");
+            //Enter exam
+            //Get patient info
+            var patientName = "";
+            var patientSex = "";
+            var patientAge = 0;
+            var examDate = DateTime.Now;
+
+            //Get report
+            var report = "";
+
+            //Save images.
+            var imageUrls = new List<string>();
+            for(var i= 0;i< imageUrls.Count;i++)
+            {
+                var response = await input.WaitForResponseAsync(imageUrls[i]);
+                var buffer = await response.BufferAsync();
+                var image = new Image()
+                {
+                    Id = Guid.NewGuid().ToString("N"),
+                    ExamId = exmaId,
+                    ImageIndex = i,
+                    Data = buffer,
+                    CreateTime = DateTime.Now,
+                };
+                db.AddImage(image);
+            }
+
+            //Save exam.
+            var exam = new Exam()
+            {
+                Id = exmaId,
+                PatientName = patientName,
+                PatientSex = patientSex,
+                PatientAge = patientAge,
+                ExamDate = examDate,
+                Report = report,
+                BatchTaskId = _batchTaskId,
+                ExamIndex = _examIndex,
+                PageIndex = _pageIndex,
+                ExamIndexInPage = _examIndexInPage,
+                CreateTime = DateTime.Now
+            };
+            db.AddExam(exam);
+            //Back to page.
+            await input.GoBackAsync();
+            return input;
+        }
+    }
+}

+ 85 - 0
StationProbe/Program.cs

@@ -0,0 +1,85 @@
+// See https://aka.ms/new-console-template for more information
+using PuppeteerSharp;
+using StationProbe;
+
+if (args.Length == 0)
+{
+    Console.WriteLine("Use one of 'create','run','list' commands to start this application.");
+}
+else
+{
+    var command = args[0];
+    if (command == "create")
+    {
+        var name = args[1];
+        var start = DateTime.Parse(args[2]);
+        var end = DateTime.Parse(args[3]);
+        using (var db = new Database())
+        {
+            db.AddBatchTask(new BatchTask() { Name = name, Start = start, End = end });
+        }
+    }
+    else if (command == "run")
+    {
+        var batchTaskId = int.Parse(args[1]);
+        var batchTask = new Database().GetBatchTask(batchTaskId);
+        if (batchTask == null)
+        {
+            Console.WriteLine($"No batch task for id:{batchTaskId}, please create batch task before run it.");
+        }
+        else
+        {
+            Console.WriteLine("Downloading headless browser...");
+            await new BrowserFetcher().DownloadAsync();
+
+            bool error = true;
+            while (error)
+            {
+                try
+                {
+                    await using (var browser = (Browser)await Puppeteer.LaunchAsync(new LaunchOptions
+                    {
+                        Headless = true
+                    }))
+                    {
+                        await using (var page = await browser.NewPageAsync())
+                        {
+                            await page.SetViewportAsync(new ViewPortOptions
+                            {
+                                Width = 1920,
+                                Height = 1080
+                            });
+                            var superImageTask = new SuperImageTask(batchTask, 15);
+                            await superImageTask.RunAsync(page);
+                            error = false;
+                        }
+
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Logger.WriteLine($"Run super image task error:{ex}");
+                    error = true;
+                }
+            }
+        }
+    }
+    else if (command == "list")
+    {
+        using (var db = new Database())
+        {
+            Console.WriteLine($"Id \t Name \t Pages \t Exams \t Start       \t End      ");
+            var batchTasks = db.GetBatchTasks();
+            foreach (var batchTask in batchTasks)
+            {
+                Console.WriteLine($"{batchTask.Id} \t {batchTask.Name} \t {batchTask.PageCount} \t {batchTask.ExamCount} \t {batchTask.Start:yyyy-MM-dd} \t {batchTask.End:yyyy-MM-dd}");
+            }
+        }
+    }
+    else
+    {
+        Console.WriteLine("Use one of 'create','run','list' commands to start this application.");
+    }
+}
+
+

+ 15 - 0
StationProbe/StationProbe.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="PuppeteerSharp" Version="12.0.0" />
+    <PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
+  </ItemGroup>
+
+</Project>

+ 115 - 0
StationProbe/SuperImageTask.cs

@@ -0,0 +1,115 @@
+using PuppeteerSharp;
+
+namespace StationProbe
+{
+    internal class SuperImageTask : IDisposable
+    {
+        private readonly Database _db;
+        private readonly BatchTask _batchTask;
+        private readonly int _examCountInPage;
+        private int _pageIndex = 1;
+        private int _examIndex = 0;
+        private int _examIndexInPage = 0;
+
+        public SuperImageTask(BatchTask batchTask, int examCountInPage)
+        {
+            _batchTask = batchTask;
+            _examCountInPage = examCountInPage;
+            _db = new Database();
+        }
+
+        public async Task RunAsync(IPage page)
+        {
+            IPage output = page;
+            var url = "http://192.168.200.85:8080";
+            Logger.WriteLine($"Start login task (url:{url})...");
+            try
+            {
+                output = await new LoginTask(url).ExecuteAsync(output,_db);
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLine($"Run LoginTask failed:{ex}");
+                throw;
+            }
+            Logger.WriteLine("Start menu task...");
+            try
+            {
+                output = await new MenuTask().ExecuteAsync(output, _db);
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLine($"Run MenuTask failed:{ex}");
+                throw;
+            }
+            Logger.WriteLine($"Start filter task(start:{_batchTask.Start:yyyy-MM-dd}, end:{_batchTask.End:yyyy-MM-dd})...");
+            try
+            {
+                var filterTask = new FilterTask(_batchTask.Start, _batchTask.End);
+                output = await filterTask.ExecuteAsync(output, _db);
+                if (filterTask.PageCount != _batchTask.PageCount || filterTask.ExamCount != _batchTask.ExamCount)
+                {
+                    //Update the batchTask
+                    _batchTask.ExamCount = filterTask.ExamCount;
+                    _batchTask.PageCount = filterTask.PageCount;
+                    _db.UpdateBatchTask(_batchTask);
+                }
+                Logger.WriteLine($"Get page count:{filterTask.PageCount}, exam count:{filterTask.ExamCount}");
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLine($"Run FilterTask failed:{ex}");
+                throw;
+            }
+
+            var lastExam = _db.GetLastExam(_batchTask.Id);
+            if (lastExam != null)
+            {
+                _pageIndex = lastExam.PageIndex;
+                _examIndex = lastExam.ExamIndex + 1;
+                _examIndexInPage = lastExam.ExamIndexInPage + 1;
+                if (_examIndexInPage + 1 == _examCountInPage)
+                {
+                    _pageIndex++;
+                    _examIndexInPage = 0;
+                }
+            }
+            Logger.WriteLine($"Start from page: {_pageIndex}, exam index: {_examIndexInPage}");
+            while (_pageIndex < _batchTask.PageCount)
+            {
+                Logger.WriteLine($"Start page task (page:{_pageIndex})");
+                try
+                {
+                    var pageTask = new PageTask(_pageIndex);
+                    output = await pageTask.ExecuteAsync(output, _db);
+                    var currentExamCountinPage = _pageIndex < (_batchTask.PageCount - 1) ? _examCountInPage : (_batchTask.ExamCount - _pageIndex * _examCountInPage);
+                    while (_examIndexInPage < currentExamCountinPage)
+                    {
+                        Logger.WriteLine($"Start exam task (exam index: {_examIndexInPage})...");
+                        try
+                        {
+                            output = await new ExamTask(_batchTask.Id, _pageIndex, _examIndex ,_examIndexInPage).ExecuteAsync(output, _db);
+                        }
+                        catch (Exception ex)
+                        {
+                            Logger.WriteLine($"Run ExamTask failed:{ex}");
+                            throw;
+                        }
+                    }
+                    _examIndexInPage = 0;
+                }
+                catch (Exception ex)
+                {
+                    Logger.WriteLine($"Run PageTask failed:{ex}");
+                    throw;
+                }
+                _pageIndex++;
+            }
+        }
+
+        public void Dispose()
+        {
+            _db.Dispose();
+        }
+    }
+}