Fix DB_TO_DEVICE HTTP restore so deleted users get face templates on device.
Use EmpIds from config when restoring from DB, and push templates via a two-step setuserinfo (create user, then backupnum/record or face) matching the F710X web API. Co-authored-by: Cursor <cursoragent@cursor.com>main
parent
6867cb90e7
commit
5424d0abb8
|
|
@ -6,12 +6,13 @@
|
||||||
providerName="MySql.Data.MySqlClient" />
|
providerName="MySql.Data.MySqlClient" />
|
||||||
</connectionStrings>
|
</connectionStrings>
|
||||||
<appSettings>
|
<appSettings>
|
||||||
<add key="ATTENDANCE_SCOPE" value="CENTRAL" />
|
<!-- <add key="ATTENDANCE_SCOPE" value="CENTRAL" /> -->
|
||||||
<!--<add key="ATTENDANCE_SCOPE" value="SITE" />-->
|
<add key="ATTENDANCE_SCOPE" value="SITE" />
|
||||||
<add key="ATTENDANCE_JOB_INTERVAL_MINUTES" value="20" />
|
<add key="ATTENDANCE_JOB_INTERVAL_MINUTES" value="20" />
|
||||||
<add key="TEMPLATE_JOB_INTERVAL_MINUTES" value="240" />
|
<add key="TEMPLATE_JOB_INTERVAL_MINUTES" value="240" />
|
||||||
<add key="TEMPLATE_SYNC_ENABLED" value="true" />
|
<add key="TEMPLATE_SYNC_ENABLED" value="true" />
|
||||||
<add key="TRANSFER_MODE" value="DEVICE_TO_DB" />
|
<add key="TRANSFER_MODE" value="DEVICE_TO_DB" />
|
||||||
|
<!-- <add key="TRANSFER_MODE" value="DB_TO_DEVICE" /> -->
|
||||||
<add key="DEVICE_SETTINGS_PATH" value="DeviceSettings.xml" />
|
<add key="DEVICE_SETTINGS_PATH" value="DeviceSettings.xml" />
|
||||||
<add key="TEMPLATE_VERIFY_AFTER_PUSH" value="true" />
|
<add key="TEMPLATE_VERIFY_AFTER_PUSH" value="true" />
|
||||||
<add key="TEMPLATE_DEVICE_DELAY_MS" value="0" />
|
<add key="TEMPLATE_DEVICE_DELAY_MS" value="0" />
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,24 @@ namespace HanvonF710XAttendanceService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetEmployeeNameForMachine(MySqlConnection connection, string machineId, string serialNumber)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(machineId) || string.IsNullOrWhiteSpace(serialNumber)) return null;
|
||||||
|
const string query =
|
||||||
|
"SELECT employee_name FROM hrms.attendance_machine_user " +
|
||||||
|
"WHERE machine_id = @MachineId AND serial_number = @SerialNumber AND is_deleted = 0 LIMIT 1";
|
||||||
|
using (var cmd = new MySqlCommand(query, connection))
|
||||||
|
{
|
||||||
|
cmd.CommandTimeout = 60;
|
||||||
|
cmd.Parameters.AddWithValue("@MachineId", machineId);
|
||||||
|
cmd.Parameters.AddWithValue("@SerialNumber", serialNumber.Trim());
|
||||||
|
var result = cmd.ExecuteScalar();
|
||||||
|
if (result == null || result == DBNull.Value) return null;
|
||||||
|
var name = result.ToString()?.Trim();
|
||||||
|
return string.IsNullOrWhiteSpace(name) ? null : name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<AttendanceMachineUser> getDBUsers(MySqlDataReader reader)
|
private List<AttendanceMachineUser> getDBUsers(MySqlDataReader reader)
|
||||||
{
|
{
|
||||||
List<AttendanceMachineUser> DbUsers = new List<AttendanceMachineUser>();
|
List<AttendanceMachineUser> DbUsers = new List<AttendanceMachineUser>();
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
<DeviceSettings Mode="Multi" SiteId="2">
|
<DeviceSettings Mode="Multi" SiteId="2">
|
||||||
<!--<Device IpAddress="192.168.70.14" Enabled="true" />-->
|
<!--<Device IpAddress="192.168.70.14" Enabled="true" />-->
|
||||||
<Device IpAddress="192.168.86.2" Enabled="true" />
|
<Device IpAddress="192.168.90.89" Enabled="true" />
|
||||||
|
|
||||||
<TemplateTransfer Enabled="false">
|
<TemplateTransfer Enabled="true">
|
||||||
<Job Id="1"
|
<Job Id="1"
|
||||||
Enabled="true"
|
Enabled="true"
|
||||||
SourceIp="192.168.86.7"
|
SourceIp="192.168.90.89"
|
||||||
EmpIds="7044">
|
EmpIds="15399,17003">
|
||||||
<Target Ip="192.168.86.4" />
|
<Target Ip="192.168.90.89" />
|
||||||
</Job>
|
</Job>
|
||||||
</TemplateTransfer>
|
</TemplateTransfer>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,121 @@ namespace HanvonF710XAttendanceService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string NormalizeFaceTemplatePayload(byte[] blob, out string pushMode)
|
||||||
|
{
|
||||||
|
pushMode = "record";
|
||||||
|
if (blob == null || blob.Length == 0) return null;
|
||||||
|
|
||||||
|
if (blob.Length >= 3 && blob[0] == 0xFF && blob[1] == 0xD8 && blob[2] == 0xFF)
|
||||||
|
{
|
||||||
|
pushMode = "face";
|
||||||
|
return Convert.ToBase64String(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
string text = Encoding.UTF8.GetString(blob).Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(text)) return null;
|
||||||
|
|
||||||
|
if (text.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
int comma = text.IndexOf(',');
|
||||||
|
if (comma >= 0) text = text.Substring(comma + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
text = text.Replace("\r", "").Replace("\n", "").Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(text)) return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] decoded = Convert.FromBase64String(text);
|
||||||
|
if (decoded.Length >= 3 && decoded[0] == 0xFF && decoded[1] == 0xD8 && decoded[2] == 0xFF)
|
||||||
|
{
|
||||||
|
pushMode = "face";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Biometric templates from getuserinfo may not decode as standard base64.
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryEnsureUser(int enrollId, string name, out string error)
|
||||||
|
{
|
||||||
|
error = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var resp = Post(new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "cmd", "setuserinfo" },
|
||||||
|
{ "password", _password },
|
||||||
|
{ "enrollid", enrollId },
|
||||||
|
{ "name", name ?? enrollId.ToString() },
|
||||||
|
{ "department", "" },
|
||||||
|
{ "shiftid", 1 },
|
||||||
|
{ "admin", 0 },
|
||||||
|
{ "pwd", 0 },
|
||||||
|
{ "card", 0 },
|
||||||
|
{ "zoneid", 0 },
|
||||||
|
{ "groupid", 0 },
|
||||||
|
{ "access_times", 0 },
|
||||||
|
{ "verifymode", 0 },
|
||||||
|
{ "birthday", "" },
|
||||||
|
{ "starttime", "" },
|
||||||
|
{ "endtime", "" },
|
||||||
|
{ "userprofile", "" }
|
||||||
|
});
|
||||||
|
if (IsSuccess(resp)) return true;
|
||||||
|
error = GetMsg(resp) ?? "setuserinfo failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
error = ex.Message;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySetFaceTemplateRecord(int enrollId, string templatePayload, string pushMode, out string error)
|
||||||
|
{
|
||||||
|
error = null;
|
||||||
|
if (string.IsNullOrWhiteSpace(templatePayload))
|
||||||
|
{
|
||||||
|
error = "template record is empty";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var payload = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "cmd", "setuserinfo" },
|
||||||
|
{ "password", _password },
|
||||||
|
{ "enrollid", enrollId }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.Equals(pushMode, "face", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
payload["face"] = templatePayload;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
payload["backupnum"] = GetIntSetting("DEVICE_FACE_BACKUPNUM", 50);
|
||||||
|
payload["record"] = templatePayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp = Post(payload);
|
||||||
|
if (IsSuccess(resp)) return true;
|
||||||
|
error = GetMsg(resp) ?? "setuserinfo template push failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
error = ex.Message;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryGetFaceRecord(int enrollId, out string recordBase64, out string name, out string error)
|
public bool TryGetFaceRecord(int enrollId, out string recordBase64, out string name, out string error)
|
||||||
{
|
{
|
||||||
recordBase64 = null;
|
recordBase64 = null;
|
||||||
|
|
@ -231,6 +346,43 @@ namespace HanvonF710XAttendanceService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryRestoreUserWithFaceTemplate(int enrollId, string name, string templatePayload, string pushMode, out string error)
|
||||||
|
{
|
||||||
|
error = null;
|
||||||
|
if (string.IsNullOrWhiteSpace(templatePayload))
|
||||||
|
{
|
||||||
|
error = "template record is empty";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryEnsureUser(enrollId, name, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int delayMs = GetIntSetting("TEMPLATE_DEVICE_DELAY_MS", 300);
|
||||||
|
if (delayMs > 0)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.Sleep(delayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TrySetFaceTemplateRecord(enrollId, templatePayload, pushMode, out error))
|
||||||
|
{
|
||||||
|
string altMode = string.Equals(pushMode, "face", StringComparison.OrdinalIgnoreCase) ? "record" : "face";
|
||||||
|
if (!TrySetFaceTemplateRecord(enrollId, templatePayload, altMode, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UserHasFaceTemplate(int enrollId, out string error)
|
||||||
|
{
|
||||||
|
return TryGetFaceRecord(enrollId, out _, out _, out error);
|
||||||
|
}
|
||||||
|
|
||||||
private Dictionary<string, object> Post(Dictionary<string, object> payload)
|
private Dictionary<string, object> Post(Dictionary<string, object> payload)
|
||||||
{
|
{
|
||||||
string body = _json.Serialize(payload);
|
string body = _json.Serialize(payload);
|
||||||
|
|
|
||||||
|
|
@ -128,24 +128,50 @@ namespace HanvonF710XAttendanceService
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryGetEmployeeIdsFromDevice(sourceMachine, out var employeeIds, logs, job.Id))
|
if (mode == TemplateTransferMode.DB_TO_DEVICE)
|
||||||
|
{
|
||||||
|
List<string> idsForTransfer;
|
||||||
|
if (job.EmpIds != null && job.EmpIds.Count > 0)
|
||||||
|
{
|
||||||
|
// Restore from DB even when user was deleted from source device.
|
||||||
|
idsForTransfer = job.EmpIds
|
||||||
|
.Where(id => !string.IsNullOrWhiteSpace(id))
|
||||||
|
.Select(id => id.Trim())
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToList();
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] DB_TO_DEVICE using EmpIds from config (source device list skipped): {string.Join(",", idsForTransfer)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!TryGetEmployeeIdsFromDevice(sourceMachine, out var employeeIds, logs, job.Id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (employeeIds.Count == 0)
|
||||||
|
{
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] Source device returned 0 employee IDs.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
idsForTransfer = employeeIds;
|
||||||
|
}
|
||||||
|
TransferDbToDevice(job, idsForTransfer, targetMachines, connection, logs);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetEmployeeIdsFromDevice(sourceMachine, out var deviceEmployeeIds, logs, job.Id))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (employeeIds.Count == 0)
|
if (deviceEmployeeIds.Count == 0)
|
||||||
{
|
{
|
||||||
logs.Add($"[TemplateJob {job.Id}] Source device returned 0 employee IDs.");
|
logs.Add($"[TemplateJob {job.Id}] Source device returned 0 employee IDs.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == TemplateTransferMode.DB_TO_DEVICE)
|
if (mode == TemplateTransferMode.DEVICE_TO_DEVICE)
|
||||||
{
|
{
|
||||||
TransferDbToDevice(job, employeeIds, targetMachines, connection, logs);
|
TransferDeviceToDevice(job.Id, sourceMachine, deviceEmployeeIds, targetMachines, logs);
|
||||||
}
|
|
||||||
else if (mode == TemplateTransferMode.DEVICE_TO_DEVICE)
|
|
||||||
{
|
|
||||||
TransferDeviceToDevice(job.Id, sourceMachine, employeeIds, targetMachines, logs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -678,9 +704,6 @@ namespace HanvonF710XAttendanceService
|
||||||
|
|
||||||
foreach (var target in targets)
|
foreach (var target in targets)
|
||||||
{
|
{
|
||||||
string targetDevInfo = target.Machine.GetDeviceInfo();
|
|
||||||
var callback = new CallBack(Program.BeCalled);
|
|
||||||
|
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
int verifyOk = 0;
|
int verifyOk = 0;
|
||||||
|
|
@ -688,53 +711,71 @@ namespace HanvonF710XAttendanceService
|
||||||
|
|
||||||
logs.Add($"[TemplateTransfer] job={job.Id} target_ip={target.Machine.MachineIp} total_templates={totalTemplates} batch_size={batchSize} total_batches={batches.Count}");
|
logs.Add($"[TemplateTransfer] job={job.Id} target_ip={target.Machine.MachineIp} total_templates={totalTemplates} batch_size={batchSize} total_batches={batches.Count}");
|
||||||
|
|
||||||
for (int bi = 0; bi < batches.Count; bi++)
|
if (DeviceProtocol.UseHttp())
|
||||||
{
|
{
|
||||||
var swBatch = Stopwatch.StartNew();
|
var httpClient = HanvonHttpApiClient.ForMachine(target.Machine);
|
||||||
int bAttempted = 0;
|
if (!httpClient.TryLogin(out string loginErr))
|
||||||
int bOk = 0;
|
|
||||||
int bFail = 0;
|
|
||||||
int bVerifyOk = 0;
|
|
||||||
int bVerifyFail = 0;
|
|
||||||
|
|
||||||
foreach (var kvp in batches[bi])
|
|
||||||
{
|
{
|
||||||
bAttempted++;
|
logs.Add($"[TemplateJob {job.Id}] HTTP login failed for target. ip={target.Machine.MachineIp} err={loginErr}");
|
||||||
string empId = kvp.Key;
|
Program.RecordUnreachableMachine(target.Machine, "DB_TO_DEVICE HTTP login: " + loginErr);
|
||||||
string templateStr = Encoding.UTF8.GetString(kvp.Value ?? Array.Empty<byte>());
|
continue;
|
||||||
if (!TemplateParser.TryBuildSetEmployeeCommand(templateStr, out var setCmd))
|
}
|
||||||
{
|
|
||||||
fail++;
|
|
||||||
bFail++;
|
|
||||||
logs.Add($"[TemplateJob {job.Id}] Build SetEmployee failed. emp={empId} target={target.Machine.MachineIp}");
|
|
||||||
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=FAIL reason=BuildSetEmployee");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string response = "";
|
var machineUserDao = new AttendanceMachineUserDAO();
|
||||||
uint recvLen = 0;
|
|
||||||
int rc = Program.test(targetDevInfo, targetDevInfo.Length, setCmd, setCmd.Length, ref response, ref recvLen, callback);
|
for (int bi = 0; bi < batches.Count; bi++)
|
||||||
if (rc != 0 || (response != null && response.IndexOf("fail", StringComparison.OrdinalIgnoreCase) >= 0))
|
{
|
||||||
{
|
var swBatch = Stopwatch.StartNew();
|
||||||
fail++;
|
int bAttempted = 0;
|
||||||
bFail++;
|
int bOk = 0;
|
||||||
logs.Add($"[TemplateJob {job.Id}] SetEmployee failed. emp={empId} target={target.Machine.MachineIp}");
|
int bFail = 0;
|
||||||
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=FAIL rc={rc}");
|
int bVerifyOk = 0;
|
||||||
}
|
int bVerifyFail = 0;
|
||||||
else
|
|
||||||
|
foreach (var kvp in batches[bi])
|
||||||
{
|
{
|
||||||
|
bAttempted++;
|
||||||
|
string empId = kvp.Key;
|
||||||
|
byte[] templateBlob = kvp.Value ?? Array.Empty<byte>();
|
||||||
|
string recordBase64 = HanvonHttpApiClient.NormalizeFaceTemplatePayload(templateBlob, out string pushMode);
|
||||||
|
if (string.IsNullOrWhiteSpace(recordBase64))
|
||||||
|
{
|
||||||
|
fail++;
|
||||||
|
bFail++;
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] Empty template payload. emp={empId} blob_bytes={templateBlob.Length} target={target.Machine.MachineIp}");
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=FAIL reason=EmptyTemplate blob_bytes={templateBlob.Length}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(empId, out int enrollId))
|
||||||
|
{
|
||||||
|
fail++;
|
||||||
|
bFail++;
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] Invalid enroll id for HTTP setuserinfo. emp={empId} target={target.Machine.MachineIp}");
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=FAIL reason=InvalidEnrollId");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string displayName = machineUserDao.GetEmployeeNameForMachine(connection, target.Machine.MachineId, empId)
|
||||||
|
?? empId;
|
||||||
|
|
||||||
|
if (!httpClient.TryRestoreUserWithFaceTemplate(enrollId, displayName, recordBase64, pushMode, out string pushErr))
|
||||||
|
{
|
||||||
|
fail++;
|
||||||
|
bFail++;
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] HTTP template push failed. emp={empId} mode={pushMode} payload_len={recordBase64.Length} target={target.Machine.MachineIp} err={pushErr}");
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} mode={pushMode} payload_len={recordBase64.Length} send=FAIL err={pushErr}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ok++;
|
ok++;
|
||||||
bOk++;
|
bOk++;
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] HTTP template push ok. emp={empId} name={displayName} mode={pushMode} payload_len={recordBase64.Length} target={target.Machine.MachineIp}");
|
||||||
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=OK");
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=OK");
|
||||||
|
|
||||||
if (verifyAfterPush)
|
if (verifyAfterPush)
|
||||||
{
|
{
|
||||||
string verifyCmd = "GetEmployee(id=\"" + empId + "\")";
|
if (httpClient.UserHasFaceTemplate(enrollId, out string verifyErr))
|
||||||
string verifyResp = "";
|
|
||||||
uint verifyRecvLen = 0;
|
|
||||||
int vrc = Program.test(targetDevInfo, targetDevInfo.Length, verifyCmd, verifyCmd.Length, ref verifyResp, ref verifyRecvLen, callback);
|
|
||||||
bool success = vrc == 0 && verifyResp != null && verifyResp.IndexOf("success", StringComparison.OrdinalIgnoreCase) >= 0;
|
|
||||||
if (success)
|
|
||||||
{
|
{
|
||||||
verifyOk++;
|
verifyOk++;
|
||||||
bVerifyOk++;
|
bVerifyOk++;
|
||||||
|
|
@ -744,19 +785,96 @@ namespace HanvonF710XAttendanceService
|
||||||
{
|
{
|
||||||
verifyFail++;
|
verifyFail++;
|
||||||
bVerifyFail++;
|
bVerifyFail++;
|
||||||
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} verify=FAIL rc={vrc}");
|
logs.Add($"[TemplateJob {job.Id}] HTTP verify failed after push. emp={empId} target={target.Machine.MachineIp} err={verifyErr}");
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} verify=FAIL err={verifyErr}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (delayMs > 0)
|
if (delayMs > 0)
|
||||||
|
{
|
||||||
|
Thread.Sleep(delayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
swBatch.Stop();
|
||||||
|
logs.Add($"[TemplateTransferBatch] job={job.Id} target_ip={target.Machine.MachineIp} batch={bi + 1}/{batches.Count} attempted={bAttempted} ok={bOk} fail={bFail} verify_ok={bVerifyOk} verify_fail={bVerifyFail} duration_sec={Math.Round(swBatch.Elapsed.TotalSeconds, 1)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string targetDevInfo = target.Machine.GetDeviceInfo();
|
||||||
|
var callback = new CallBack(Program.BeCalled);
|
||||||
|
|
||||||
|
for (int bi = 0; bi < batches.Count; bi++)
|
||||||
{
|
{
|
||||||
System.Threading.Thread.Sleep(delayMs);
|
var swBatch = Stopwatch.StartNew();
|
||||||
}
|
int bAttempted = 0;
|
||||||
|
int bOk = 0;
|
||||||
|
int bFail = 0;
|
||||||
|
int bVerifyOk = 0;
|
||||||
|
int bVerifyFail = 0;
|
||||||
|
|
||||||
swBatch.Stop();
|
foreach (var kvp in batches[bi])
|
||||||
logs.Add($"[TemplateTransferBatch] job={job.Id} target_ip={target.Machine.MachineIp} batch={bi + 1}/{batches.Count} attempted={bAttempted} ok={bOk} fail={bFail} verify_ok={bVerifyOk} verify_fail={bVerifyFail} duration_sec={Math.Round(swBatch.Elapsed.TotalSeconds, 1)}");
|
{
|
||||||
|
bAttempted++;
|
||||||
|
string empId = kvp.Key;
|
||||||
|
string templateStr = Encoding.UTF8.GetString(kvp.Value ?? Array.Empty<byte>());
|
||||||
|
if (!TemplateParser.TryBuildSetEmployeeCommand(templateStr, out var setCmd))
|
||||||
|
{
|
||||||
|
fail++;
|
||||||
|
bFail++;
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] Build SetEmployee failed. emp={empId} target={target.Machine.MachineIp}");
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=FAIL reason=BuildSetEmployee");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string response = "";
|
||||||
|
uint recvLen = 0;
|
||||||
|
int rc = Program.test(targetDevInfo, targetDevInfo.Length, setCmd, setCmd.Length, ref response, ref recvLen, callback);
|
||||||
|
if (rc != 0 || (response != null && response.IndexOf("fail", StringComparison.OrdinalIgnoreCase) >= 0))
|
||||||
|
{
|
||||||
|
fail++;
|
||||||
|
bFail++;
|
||||||
|
logs.Add($"[TemplateJob {job.Id}] SetEmployee failed. emp={empId} target={target.Machine.MachineIp}");
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=FAIL rc={rc}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok++;
|
||||||
|
bOk++;
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} send=OK");
|
||||||
|
|
||||||
|
if (verifyAfterPush)
|
||||||
|
{
|
||||||
|
string verifyCmd = "GetEmployee(id=\"" + empId + "\")";
|
||||||
|
string verifyResp = "";
|
||||||
|
uint verifyRecvLen = 0;
|
||||||
|
int vrc = Program.test(targetDevInfo, targetDevInfo.Length, verifyCmd, verifyCmd.Length, ref verifyResp, ref verifyRecvLen, callback);
|
||||||
|
bool success = vrc == 0 && verifyResp != null && verifyResp.IndexOf("success", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
verifyOk++;
|
||||||
|
bVerifyOk++;
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} verify=OK");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verifyFail++;
|
||||||
|
bVerifyFail++;
|
||||||
|
Program.WriteInternalLog($"[DB_TO_DEVICE] job={job.Id} target={target.Machine.MachineIp} emp={empId} verify=FAIL rc={vrc}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delayMs > 0)
|
||||||
|
{
|
||||||
|
Thread.Sleep(delayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
swBatch.Stop();
|
||||||
|
logs.Add($"[TemplateTransferBatch] job={job.Id} target_ip={target.Machine.MachineIp} batch={bi + 1}/{batches.Count} attempted={bAttempted} ok={bOk} fail={bFail} verify_ok={bVerifyOk} verify_fail={bVerifyFail} duration_sec={Math.Round(swBatch.Elapsed.TotalSeconds, 1)}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verifyAfterPush)
|
if (verifyAfterPush)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue