Compare commits
No commits in common. "14b49d38a20e65708ff1b10ff727cd56a93981e8" and "a4d411bcb7b14d3655a5fcdd870101e83ef4449b" have entirely different histories.
14b49d38a2
...
a4d411bcb7
|
@ -8,10 +8,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.NetCore" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="7.0.15" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
|
||||
<PackageReference Include="Quartz" Version="3.10.0" />
|
||||
<PackageReference Include="sqlite-net-sqlcipher" Version="1.9.172" />
|
||||
<PackageReference Include="System.Management" Version="8.0.0"/>
|
||||
<PackageReference Include="Serilog" Version="4.0.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00972"/>
|
||||
|
@ -39,8 +36,4 @@
|
|||
<None Remove=".gitignore" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Service\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
namespace MasstransferCommon.Model.Entity;
|
||||
|
||||
public enum ChipColorEnum
|
||||
{
|
||||
R = 1,
|
||||
G = 2,
|
||||
B = 3
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using SQLite;
|
||||
|
||||
namespace MasstransferCommon.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库实体的父类
|
||||
/// </summary>
|
||||
public class Entity
|
||||
{
|
||||
[PrimaryKey] public string? Id { get; set; }
|
||||
|
||||
[Column("create_time")] public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
|
||||
[Column("update_time")] public DateTime UpdateTime { get; set; } = DateTime.Now;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
using System.ComponentModel;
|
||||
using SQLite;
|
||||
|
||||
namespace MasstransferCommon.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 日志参数
|
||||
/// </summary>
|
||||
[Table("log_params")]
|
||||
[Description("日志参数")]
|
||||
public class LogParams : Entity
|
||||
{
|
||||
[Column("level"), Description("日志级别")] public string? Level { get; set; }
|
||||
|
||||
[Column("path"), Description("日志存放路径")]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[Column("upload_corn"), Description("日志上传时间")]
|
||||
public string? UploadCorn { get; set; }
|
||||
|
||||
[Column("upload_levels"), Description("日志上传级别")]
|
||||
public string? UploadLevels { get; set; }
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.ComponentModel;
|
||||
using SQLite;
|
||||
|
||||
namespace MasstransferCommon.Model.Entity;
|
||||
|
||||
[Table("message_failure_record"), Description("消息发送失败记录")]
|
||||
public class MessageFailureRecord : Entity
|
||||
{
|
||||
[Column("topic"), Description("主题")] public string Topic { get; set; }
|
||||
|
||||
[Column("payload"), Description("消息内容")]
|
||||
public string Payload { get; set; }
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
using System.ComponentModel;
|
||||
using MasstransferCommon.Model.Enum;
|
||||
using SQLite;
|
||||
|
||||
namespace MasstransferCommon.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 基板信息
|
||||
/// </summary>
|
||||
[Table("substrates")]
|
||||
public class Substrate : Entity
|
||||
{
|
||||
[Column("context_id"), Description("上下文ID")]
|
||||
public string? ContextId { get; set; }
|
||||
|
||||
[Column("substrate_code"), Description("基板编号")]
|
||||
public string SubstrateCode { get; set; }
|
||||
|
||||
[Column("jig_code"), Description("治具编号")]
|
||||
public string JigCode { get; set; }
|
||||
|
||||
[Column("substrate_type"), Description("基板类型")]
|
||||
public SubstrateTypeEnum SubstrateType { get; set; }
|
||||
|
||||
[Column("row"), Description("基板行")] public int Row { get; set; }
|
||||
|
||||
[Column("column"), Description("基板列")] public int Column { get; set; }
|
||||
|
||||
[Column("batch_no"), Description("批次号")]
|
||||
public string BatchNo { get; set; }
|
||||
|
||||
[Column("formula_id"), Description("配方ID")]
|
||||
public string FormulaId { get; set; }
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using System.ComponentModel;
|
||||
using SQLite;
|
||||
|
||||
namespace MasstransferCommon.Model.Entity;
|
||||
|
||||
[Table("wafers"), Description("晶环信息")]
|
||||
public class Wafer : Entity
|
||||
{
|
||||
[Column("wafer_code"), Description("晶片编号")]
|
||||
public string? WaferCode { get; set; }
|
||||
|
||||
[Column("color"), Description("晶片颜色")] public ChipColorEnum Color { get; set; }
|
||||
|
||||
[Column("context_id"), Description("上下文id")]
|
||||
public string? ContextId { get; set; }
|
||||
|
||||
[Column("column"), Description("列")] public int Column { get; set; }
|
||||
|
||||
[Column("row"), Description("行")] public int Row { get; set; }
|
||||
|
||||
[Column("used"), Description("是否已使用")] public bool Used { get; set; }
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using System.ComponentModel;
|
||||
using SQLite;
|
||||
|
||||
namespace MasstransferCommon.Model.Entity;
|
||||
|
||||
[Table("wafer_used_record"), Description("晶环使用记录")]
|
||||
public class WaferUsedRecord : Entity
|
||||
{
|
||||
[Column("context_id"), Description("上下文编号")]
|
||||
public string? ContextId { get; set; }
|
||||
|
||||
[Column("wafer_code"), Description("晶环编号")]
|
||||
public string? WaferCode { get; set; }
|
||||
|
||||
[Column("substrate_code"), Description("基板编号")]
|
||||
public string? SubstrateCode { get; set; }
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
namespace MasstransferCommon.Model.Enum;
|
||||
|
||||
/// <summary>
|
||||
/// 防止注册表被恶意篡改,这里的注册许可类型需要做一些混淆
|
||||
/// </summary>
|
||||
public enum LicenseTypeEnum
|
||||
{
|
||||
// 临时许可
|
||||
Temporary = unchecked(int.MaxValue - 123456),
|
||||
|
||||
// 正式许可
|
||||
Formal = unchecked(int.MaxValue - 123457)
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
namespace MasstransferCommon.Model.Enum;
|
||||
|
||||
/// <summary>
|
||||
/// 锁定状态
|
||||
/// </summary>
|
||||
public enum LockStateEnum
|
||||
{
|
||||
// 锁定状态
|
||||
LockedState = int.MaxValue / 3,
|
||||
|
||||
// 等待锁定状态
|
||||
WaitToLockedState = int.MaxValue / 4,
|
||||
|
||||
// 解锁状态
|
||||
UnLockedState = int.MaxValue / 5,
|
||||
|
||||
// 等待解锁状态
|
||||
WaitToUnLockedState = int.MaxValue / 6
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace MasstransferCommon.Model.Enum;
|
||||
|
||||
/// <summary>
|
||||
/// 基材类型
|
||||
/// </summary>
|
||||
public enum SubstrateTypeEnum
|
||||
{
|
||||
[Description("PCB")] PCB = 1,
|
||||
[Description("玻璃")] Glass = 2
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
using Quartz;
|
||||
using Quartz.Impl;
|
||||
using Serilog;
|
||||
|
||||
namespace MasstransferCommon.scheduler;
|
||||
|
||||
public class SchedulerHelper
|
||||
{
|
||||
private static readonly Lazy<IScheduler> lazyScheduler = new(() => InitSchedulerAsync().GetAwaiter().GetResult());
|
||||
|
||||
private static readonly Dictionary<string, IJobDetail> _jobDetails = new();
|
||||
|
||||
private static IScheduler Scheduler => lazyScheduler.Value;
|
||||
|
||||
private static async Task<IScheduler> InitSchedulerAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await new StdSchedulerFactory().GetScheduler();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"Failed to initialize scheduler: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task Start()
|
||||
{
|
||||
await Scheduler.Start();
|
||||
}
|
||||
|
||||
public static async Task SchedulerInterval<T>(Dictionary<string, object>? data, int interval,
|
||||
string group = "defaultGroup") where T : IJob
|
||||
{
|
||||
var job = CreateJob<T>(data, group);
|
||||
|
||||
var trigger = TriggerBuilder.Create()
|
||||
.WithIdentity(typeof(T).Name, group)
|
||||
.StartNow()
|
||||
.WithSimpleSchedule(x => x.WithIntervalInSeconds(interval).RepeatForever())
|
||||
.Build();
|
||||
|
||||
await Scheduler.ScheduleJob(job, trigger);
|
||||
}
|
||||
|
||||
public static async Task SchedulerCorn<T>(Dictionary<string, object>? data, string? cronExpression,
|
||||
string group = "defaultGroup") where T : IJob
|
||||
{
|
||||
var job = CreateJob<T>(data, group);
|
||||
|
||||
var trigger = TriggerBuilder.Create()
|
||||
.WithIdentity(typeof(T).Name, group)
|
||||
.StartNow()
|
||||
.WithSchedule(CronScheduleBuilder.CronSchedule(cronExpression))
|
||||
.Build();
|
||||
|
||||
await Scheduler.ScheduleJob(job, trigger);
|
||||
}
|
||||
|
||||
private static IJobDetail CreateJob<T>(Dictionary<string, object>? data, string group) where T : IJob
|
||||
{
|
||||
if (_jobDetails.ContainsKey(typeof(T).Name)) return _jobDetails[typeof(T).Name];
|
||||
|
||||
var job = JobBuilder.Create<T>()
|
||||
.WithIdentity(typeof(T).Name, group)
|
||||
.Build();
|
||||
|
||||
if (data != null && data.Count > 0)
|
||||
foreach (var item in data)
|
||||
job.JobDataMap.Add(item.Key, item.Value);
|
||||
|
||||
_jobDetails[typeof(T).Name] = job;
|
||||
return job;
|
||||
}
|
||||
|
||||
public static async Task PauseJob<T>(string group = "defaultGroup")
|
||||
{
|
||||
if (_jobDetails.ContainsKey(typeof(T).Name)) await Scheduler.PauseJob(JobKey.Create(typeof(T).Name, group));
|
||||
}
|
||||
|
||||
public static async Task ResumeJob<T>(string group = "defaultGroup")
|
||||
{
|
||||
if (_jobDetails.ContainsKey(typeof(T).Name)) await Scheduler.ResumeJob(JobKey.Create(typeof(T).Name, group));
|
||||
}
|
||||
|
||||
public static async Task Shutdown()
|
||||
{
|
||||
if (!Scheduler.IsShutdown) await Scheduler.Shutdown();
|
||||
}
|
||||
|
||||
public static async Task TriggerOnceImmediately<T>(string group = "defaultGroup") where T : IJob
|
||||
{
|
||||
if (!_jobDetails.ContainsKey(typeof(T).Name)) return;
|
||||
|
||||
await Scheduler.TriggerJob(new JobKey(typeof(T).Name, group));
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
namespace MasstransferExporter.DataExporter.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 动打记录
|
||||
/// 每次基板动打完成后进行触发上传
|
||||
/// </summary>
|
||||
public class StrikeRecord
|
||||
{
|
||||
public string BatchNumber { get; set; }
|
||||
public string PcbNumber { get; set; }
|
||||
public string ChipType { get; set; }
|
||||
public string HitQuantity { get; set; }
|
||||
public string PcbInputTimeCost { get; set; }
|
||||
public string PcbScanTimeCost { get; set; }
|
||||
public string PcbOutputTimeCost { get; set; }
|
||||
public List<StrikeWaferRecord> Rounds { get; set; }
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
namespace MasstransferExporter.DataExporter.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 每次动打期间用到的wafer记录
|
||||
/// </summary>
|
||||
public class StrikeWaferRecord
|
||||
{
|
||||
public string WaferNumber { get; set; }
|
||||
public string ChipQuantity { get; set; }
|
||||
public string WaferInputTimeCost { get; set; }
|
||||
public string ChipScanTimeCost { get; set; }
|
||||
public string ProdutionTimeCost { get; set; }
|
||||
public string PcbCheckTimeCost { get; set; }
|
||||
public string WaferOutputTimeCost { get; set; }
|
||||
public string HitedQuantity { get; set; }
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
namespace MasstransferExporter.DataExporter;
|
||||
|
||||
public class StrikeRecordService
|
||||
{
|
||||
/// <summary>
|
||||
/// 上报动打记录
|
||||
/// </summary>
|
||||
private static void ReportStrikeRecord()
|
||||
{
|
||||
// 根据这个基板编号,从记录中找到所有的跟基板有关的生产记录
|
||||
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
namespace MasstransferExporter.LogExporter;
|
||||
|
||||
public class LogFileExporter
|
||||
{
|
||||
public async Task Export(string logFilePath)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -34,8 +34,4 @@
|
|||
<None Remove="obj\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ImageExporter\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,22 +1,7 @@
|
|||
using MasstransferExporter.RemoteControl;
|
||||
using MasstransferExporter.RemoteControl.Model;
|
||||
|
||||
class Program
|
||||
class Program
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
Thread.Sleep(30000);
|
||||
|
||||
var cmd = new LockCmd
|
||||
{
|
||||
Action = 1,
|
||||
ExpiryTime = 0,
|
||||
LockType = 0
|
||||
};
|
||||
|
||||
RemoteLockService.HandleLockCmd(cmd);
|
||||
|
||||
|
||||
Console.WriteLine("按任意键退出");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
namespace MasstransferExporter.RemoteControl.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 锁机指令
|
||||
/// </summary>
|
||||
public class LockCmd
|
||||
{
|
||||
/// <summary>
|
||||
/// 0 锁机 1 解锁
|
||||
/// </summary>
|
||||
public int Action { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 0 立即执行
|
||||
/// 1 到期执行
|
||||
/// </summary>
|
||||
public int LockType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到期时间
|
||||
/// </summary>
|
||||
public long ExpiryTime { get; set; }
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
using MasstransferCommon.Model.Enum;
|
||||
using MasstransferCommon.Utils;
|
||||
using MasstransferExporter.RemoteControl.Model;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace MasstransferExporter.RemoteControl;
|
||||
|
||||
/// <summary>
|
||||
/// 远程锁定服务
|
||||
/// </summary>
|
||||
public class RemoteLockService
|
||||
{
|
||||
private const string KeyPath = @"Software\Masstransfer\Security";
|
||||
|
||||
/// <summary>
|
||||
/// 处理接收到锁机业务指令
|
||||
/// </summary>
|
||||
public static void HandleLockCmd(LockCmd cmd)
|
||||
{
|
||||
var action = cmd.Action;
|
||||
|
||||
if (action == 0)
|
||||
{
|
||||
// 更新注册表锁机状态
|
||||
var lockType = cmd.LockType;
|
||||
if (lockType == 0)
|
||||
{
|
||||
RegistryHelper.WriteValue(KeyPath, "LockState", LockStateEnum.LockedState, RegistryValueKind.DWord);
|
||||
}
|
||||
else
|
||||
{
|
||||
RegistryHelper.WriteValue(KeyPath, "LockState", LockStateEnum.WaitToLockedState,
|
||||
RegistryValueKind.DWord);
|
||||
// 写入超时的时间
|
||||
RegistryHelper.WriteValue(KeyPath, "ExpireTime", cmd.ExpiryTime, RegistryValueKind.DWord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 解锁
|
||||
var lockType = cmd.LockType;
|
||||
if (lockType == 0)
|
||||
{
|
||||
RegistryHelper.WriteValue(KeyPath, "LockState", LockStateEnum.UnLockedState,
|
||||
RegistryValueKind.DWord);
|
||||
}
|
||||
else
|
||||
{
|
||||
RegistryHelper.WriteValue(KeyPath, "LockState", LockStateEnum.WaitToUnLockedState,
|
||||
RegistryValueKind.DWord);
|
||||
// 写入等待解锁超时的时间
|
||||
RegistryHelper.WriteValue(KeyPath, "ExpireTime", cmd.ExpiryTime, RegistryValueKind.DWord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,11 +15,7 @@ public class SqliteHelper
|
|||
private const string Password = "88888888";
|
||||
private readonly SQLiteConnection _db;
|
||||
|
||||
private static SqliteHelper? _instance;
|
||||
|
||||
private static readonly object Locker = new();
|
||||
|
||||
private SqliteHelper()
|
||||
public SqliteHelper()
|
||||
{
|
||||
var profile = Environment.GetEnvironmentVariable("USERPROFILE");
|
||||
var path = Path.Combine(profile, "masstransfer", "mass-transfer.db");
|
||||
|
@ -38,17 +34,6 @@ public class SqliteHelper
|
|||
_db.Execute($"PRAGMA key = '{Password}'");
|
||||
}
|
||||
|
||||
public static SqliteHelper GetInstance()
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
// 如果类的实例不存在则创建,否则直接返回
|
||||
_instance ??= new SqliteHelper();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 插入数据
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using MasstransferCommon.Model.Entity;
|
||||
using System.Reflection;
|
||||
using MasstransferCommon.Utils;
|
||||
using MasstransferInfrastructure.Database.Sqlite;
|
||||
using MasstransferInfrastructure.Mqtt.Model;
|
||||
using MQTTnet;
|
||||
using MQTTnet.Client;
|
||||
|
@ -11,8 +10,6 @@ namespace MasstransferInfrastructure.Mqtt.Client;
|
|||
|
||||
public class MessageQueueHelper
|
||||
{
|
||||
private static readonly SqliteHelper Helper = SqliteHelper.GetInstance();
|
||||
|
||||
private static readonly Dictionary<string, List<Delegate>> Subscribers = new();
|
||||
|
||||
private static readonly MqttClient Client = new();
|
||||
|
@ -66,29 +63,7 @@ public class MessageQueueHelper
|
|||
public static async Task<bool> Publish(string topic, object message,
|
||||
MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtMostOnce)
|
||||
{
|
||||
try
|
||||
{
|
||||
var isSuccess = await Client.Publish(topic, message, qos);
|
||||
if (!isSuccess)
|
||||
{
|
||||
throw new Exception("发送消息失败");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MessageFailureRecord record = new()
|
||||
{
|
||||
Payload = JsonUtil.ToJson(message),
|
||||
Topic = topic
|
||||
};
|
||||
|
||||
// 将当前消息记录到数据库
|
||||
Helper.Insert(record);
|
||||
|
||||
return false;
|
||||
}
|
||||
return await Client.Publish(topic, message, qos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -112,7 +87,7 @@ public class MessageQueueHelper
|
|||
var methodInfo = subscriber.Method;
|
||||
var parameters = methodInfo.GetParameters();
|
||||
if (parameters.Length != 2) continue;
|
||||
var type = parameters[1].ParameterType;
|
||||
var type = parameters[1].ParameterType;
|
||||
// 通知订阅者
|
||||
subscriber.DynamicInvoke(topic, JsonUtil.FromJson(type, message));
|
||||
}
|
||||
|
|
|
@ -108,13 +108,12 @@ class MqttClient
|
|||
|
||||
var payload = message as string ?? JsonUtil.ToJson(message);
|
||||
|
||||
var result = await _client.PublishAsync(new MqttApplicationMessageBuilder()
|
||||
await _client.PublishAsync(new MqttApplicationMessageBuilder()
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithQualityOfServiceLevel(qos)
|
||||
.Build());
|
||||
|
||||
return result.IsSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
Loading…
Reference in New Issue