{*******************************************************} { } { ProcessPrint } { } { Copyright (C) 2025 kku } { } {*******************************************************} unit ProcessPrint; interface uses Winapi.Windows, System.SysUtils, System.Classes, IdHTTP, Tocsg.Obj, System.Generics.Collections, System.JSON.Types; type TxPrtData = (xpdEmp, xpdPrts, xpdBill, xpdMkcd, xpdLump); TxPrtDatas = set of TxPrtData; // PxBillEnt = ^TxBillEnt; // TxBillEnt = packed record // accessUser, // billCodeName: UTF8String; // end; TxBillData = class(TTgObject) private DcData_: TDictionary; // DataList_: TList; // StrList_: TStringList; // procedure OnEntNoti(Sender: TObject; const Item: PxBillEnt; Action: TCollectionNotification); public Constructor Create; Destructor Destroy; override; function LoadFromFile(const sPath: String): Boolean; procedure UpdateData(const sJsonData: String); procedure SaveToFile(const sPath: String); end; TxEmpData = class(TTgObject) private DcData_: TDictionary; public Constructor Create; Destructor Destroy; override; function LoadFromFile(const sPath: String): Boolean; procedure UpdateData(const sJsonData: String); procedure SaveToFile(const sPath: String); end; TxPrtInfoData = class(TTgObject) private DcData_: TDictionary; public Constructor Create; Destructor Destroy; override; function LoadFromFile(const sPath: String): Boolean; procedure UpdateData(const sJsonData: String); procedure SaveToFile(const sPath: String); end; // mk-codes, lumpsum-fixed-codes 처리 TxStrData = class(TTgObject) private sName_: String; DataList_: TStringList; public Constructor Create(sName: String); Destructor Destroy; override; function LoadFromFile(const sPath: String): Boolean; procedure UpdateData(const sJsonData: String); procedure SaveToFile(const sPath: String); end; procedure ProcessCheck_xPrintData(aHTTP: TIdHTTP); function ProcessRcv_xPrintData(aHTTP: TIdHTTP; aPrtDatas: TxPrtDatas; bForceDl: Boolean = false): Boolean; procedure CheckAndUpdate_xPrint; implementation uses Tocsg.Safe, ManagerService, Tocsg.Exception, Tocsg.Process, System.Zip, Tocsg.Shell, GlobalDefine, ProcessUninstall, Tocsg.Files, Tocsg.Trace, Tocsg.Path, Tocsg.Strings, superobject, ManagerModel, Condition, System.IniFiles, Tocsg.Json, System.JSON, System.JSON.Readers, Tocsg.DateTime, Tocsg.DRM.Encrypt; const PASS_xDRM_HEAD: AnsiString = '#df12mf8(zfq@'; PASS_xDRM_DATA: AnsiString = 'Z!8r]Xc3$g>+Tp5L%u'; SIG_xDRM: AnsiString = 'X-PRINT'; function Is_xEncrypt(const plainPath: string): Boolean; var dec: TTgDrmDec; begin try Result := CheckSign(plainPath, SIG_xDRM); except on E: Exception do begin Result := false; ETgException.TraceException(E, 'Fail .. Is_xEncrypt()'); end; end; end; function Do_xDecrypt(const encPath, decPath: string): Boolean; var dec: TTgDrmDec; begin Result := false; try if not FileExists(encPath) then exit; if not DirectoryExists(ExtractFilePath(decPath)) then exit; Guard(dec, TTgDrmDec.Create(encPath)); if not dec.CheckSig(SIG_xDRM) then exit; if not dec.ExtrHead(PASS_xDRM_HEAD) then exit; Result := dec.DecryptToFile(PASS_xDRM_DATA, decPath); except on E: Exception do ETgException.TraceException(E, 'Fail .. Do_xDecrypt()'); // WriteLn(encPath + '오류 발생: ', E.Message); end; end; function Do_xEncrypt(const plainPath, encPath: string): Boolean; var enc: TTgDrmEnc; begin Result := false; if Is_xEncrypt(plainPath) then exit; try Guard(enc, TTgDrmEnc.Create(encPath)); enc.SetHaed(PASS_xDRM_HEAD, SIG_xDRM, '', '', '', '', 0); Result := enc.EncryptFromFile(PASS_xDRM_DATA, plainPath); except on E: Exception do ETgException.TraceException(E, 'Fail .. Do_xEncrypt()'); end; end; { TxBillData } Constructor TxBillData.Create; begin Inherited Create; DcData_ := TDictionary.Create; // DcData_.OnValueNotify := OnEntNoti; // DataList_ := TList.Create; // DataList_.OnNotify := OnEntNoti; // StrList_ := TStringList.Create; end; Destructor TxBillData.Destroy; begin FreeAndNil(DcData_); // FreeAndNil(StrList_); // FreeAndNil(DataList_); Inherited; end; //procedure TxBillData.OnEntNoti(Sender: TObject; const Item: PxBillEnt; Action: TCollectionNotification); //begin // if Action = cnRemoved then // Dispose(Item); //end; function TxBillData.LoadFromFile(const sPath: String): Boolean; var // O: ISuperObject; i: Integer; sData, sDecPath: String; // pEnt: PxBillEnt; // Ent: TxBillEnt; // JSONObj: TJSONObject; // JSONArray: TJSONArray; // item: TJSONValue; ms: TMemoryStream; sr: TStreamReader; jr: TJsonTextReader; bArray, bObject: Boolean; sProp, s1, s2: String; begin Result := false; try sDecPath := ''; DcData_.Clear; // StrList_.Clear; // DataList_.Clear; // 속도 및 메모리 최적화를 위해 아래처럼 처리 25_1023 16:10:36 kku Guard(ms, TMemoryStream.Create); if Is_xEncrypt(sPath) then begin sDecPath := GetRunExePathDir + 'Task\'; if ForceDirectories(sDecPath) then begin sDecPath := sDecPath + IntToStr(GetTickCount) + '_Bil.dat'; if not Do_xDecrypt(sPath, sDecPath) then begin _Trace('Fail .. Do_xDecrypt() .. Path=%s', [sDecPath]); exit; end; ms.LoadFromFile(sDecPath); end else begin _Trace('Fail .. CreateDir() .. Path=%s', [sDecPath]); exit; end; end else ms.LoadFromFile(sPath); try Guard(sr, TStreamReader.Create(ms, TEncoding.UTF8, true, 1 shl 16)); Guard(jr, TJsonTextReader.Create(sr)); bArray := false; bObject := false; // pEnt := nil; while jr.Read do begin case jr.TokenType of TJsonToken.StartArray: bArray := true; TJsonToken.EndArray: bArray := false; TJsonToken.StartObject: begin // 객체 시작: 필요한 필드 초기화 bObject := true; // New(pEnt); // ZeroMemory(pEnt, SizeOf(TxBillEnt)); // ZeroMemory(@Ent, SizeOf(TxBillEnt)); end; TJsonToken.PropertyName: sProp := jr.Value.AsString; // Delphi 11+에서 사용 가능(버전에 따라 ToString 사용) TJsonToken.String: if bObject then begin // if pEnt <> nil then begin if SameText(sProp, 'accessUser') then s1 := jr.Value.AsString// ToString else if SameText(sProp, 'billCodeName') then s2 := jr.Value.AsString; //ToString; end; end; TJsonToken.Integer: if bObject then begin // if SameText(sProp, 'age') then // nVal := StrToIntDef(jr.Value.ToString, -1); end; TJsonToken.EndObject: begin // ★ 여기서 한 레코드 처리(저장/집계/필터링 등) 후 버린다 // 예: DB Insert, 파일 Append, 통계 누적 등 // DoProcess(sVal, nVal); bObject := false; if s2 <> '' then DcData_.Add(UpperCase(s2), s1 + '|' + s2); // if pEnt <> nil then // begin // try // if pEnt.accessUser <> '' then //// DataList_.Add(pEnt) // DcData_.Add(UpperCase(pEnt.billCodeName), pEnt) // else // Dispose(pEnt); // except // _Trace('Fail .. TxBillData.LoadFromFile() .. 중복 데이터? billCodeName=%s', [pEnt.billCodeName], 9); // Dispose(pEnt); // end; // pEnt := nil; // end; end; end; end; Result := true; finally if sDecPath <> '' then DeleteFile(sDecPath); end; // sData := LoadStrFromFile(sPath, TEncoding.UTF8); // JSONArray := TJSONObject.ParseJSONValue(sData) as TJSONArray; // if JSONArray = nil then // exit; // // try // for i := 0 to JSONArray.Count - 1 do // begin // item := JSONArray.Items[i]; // // New(pEnt); // pEnt.accessUser := item.GetValue('accessUser'); // pEnt.billCodeName := item.GetValue('billCodeName'); // try // if pEnt.accessUser <> '' then // DcData_.Add(pEnt.billCodeName.ToUpper, pEnt) // else // Dispose(pEnt); // except // _Trace('Fail .. TxBillData.LoadFromFile() .. 중복 데이터? billCodeName=%s', [pEnt.billCodeName], 9); // Dispose(pEnt); // end; // end; // finally // JSONArray.Free; // end; // if not LoadJsonObjFromFile(O, sPath) then // exit; // // if (O.DataType <> stArray) or (O.AsArray.Length = 0) then // exit; // // for i := 0 to O.AsArray.Length - 1 do // begin // New(pEnt); // pEnt.accessUser := O.AsArray.O[i].S['accessUser']; // pEnt.billCodeName := O.AsArray.O[i].S['billCodeName']; // try // if pEnt.accessUser <> '' then // DcData_.Add(pEnt.billCodeName.ToUpper, pEnt) // else // Dispose(pEnt); // except // _Trace('Fail .. TxBillData.LoadFromFile() .. 중복 데이터? billCodeName=%s', [pEnt.billCodeName], 9); // Dispose(pEnt); // end; // end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()'); end; end; procedure TxBillData.UpdateData(const sJsonData: String); var O: ISuperObject; i: Integer; sKey: String; // pEnt: PxBillEnt; begin try O := SO(sJsonData); if O = nil then exit; if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then begin for i := 0 to O.A['created'].Length - 1 do begin sKey := O.A['created'].O[i].S['billCodeName'].ToUpper; if not DcData_.ContainsKey(sKey) then begin // New(pEnt); // pEnt.billCodeName := O.A['created'].O[i].S['billCodeName']; // pEnt.accessUser := O.A['created'].O[i].S['accessUser']; // DcData_.Add(sKey, pEnt); DcData_.Add(sKey, O.A['created'].O[i].S['accessUser'] + '|' + O.A['created'].O[i].S['billCodeName']); _Trace('billcodes.UpdateData() .. created, billCodeName=%s, accessUser=%s', [O.A['created'].O[i].S['billCodeName'], O.A['created'].O[i].S['accessUser']], 5); end else begin // pEnt := DcData_[sKey]; // pEnt.accessUser := O.A['created'].O[i].S['accessUser']; DcData_[sKey] := O.A['created'].O[i].S['accessUser'] + '|' + O.A['created'].O[i].S['billCodeName']; _Trace('billcodes.UpdateData() .. created(mod), billCodeName=%s, accessUser=%s', [O.A['created'].O[i].S['billCodeName'], O.A['created'].O[i].S['accessUser']], 5); end; end; end; if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then begin for i := 0 to O.A['updated'].Length - 1 do begin sKey := O.A['updated'].O[i].S['billCodeName'].ToUpper; if not DcData_.ContainsKey(sKey) then begin // New(pEnt); // pEnt.billCodeName := O.A['updated'].O[i].S['billCodeName']; // pEnt.accessUser := O.A['updated'].O[i].S['accessUser']; // DcData_.Add(sKey, pEnt); DcData_.Add(sKey, O.A['updated'].O[i].S['accessUser'] + '|' + O.A['updated'].O[i].S['billCodeName']); _Trace('billcodes.UpdateData() .. updated(new), billCodeName=%s, accessUser=%s', [O.A['updated'].O[i].S['billCodeName'], O.A['updated'].O[i].S['accessUser']], 5); end else begin // pEnt := DcData_[sKey]; // pEnt.accessUser := O.A['updated'].O[i].S['accessUser']; DcData_[sKey] := O.A['updated'].O[i].S['accessUser'] + '|' + O.A['updated'].O[i].S['billCodeName']; _Trace('billcodes.UpdateData() .. updated, billCodeName=%s, accessUser=%s', [O.A['updated'].O[i].S['billCodeName'], O.A['updated'].O[i].S['accessUser']], 5); end; end; end; if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then begin for i := 0 to O.A['deleted'].Length - 1 do begin sKey := O.A['deleted'].O[i].S['billCodeName'].ToUpper; if DcData_.ContainsKey(sKey) then begin DcData_.Remove(O.A['deleted'].O[i].S['billCodeName'].ToUpper); _Trace('billcodes.UpdateData() .. deleted, billCodeName=%s, accessUser=%s', [O.A['deleted'].O[i].S['billCodeName'], O.A['deleted'].O[i].S['accessUser']], 5); end; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. UpdateData()'); end; end; procedure TxBillData.SaveToFile(const sPath: String); var // OA, O: ISuperObject; enum: TEnumerator; sData, sEnt, sU, sB: String; n: Integer; begin try sData := ''; // OA := TSuperObject.Create(stArray); // Guard(enum, StrList_.GetEnumerator); Guard(enum, DcData_.Values.GetEnumerator); // Guard(enum, DataList_.GetEnumerator); while enum.MoveNext do begin // SumString(sData, TTgJson.ValueToJsonAsString(enum.Current^), ','); // sEnt := JsonEscapeString(enum.Current); sEnt := enum.Current; n := Pos('|', sEnt); if n > 0 then begin sU := Copy(sEnt, 1, n - 1); Delete(sEnt, 1, n); sB := sEnt; SumString(sData, Format('{"accessUser":"%s","billCodeName":"%s"}', [sU, sB]), ','); end; // O := TTgJson.ValueToJsonObject(enum.Current^); // OA.AsArray.Add(O); end; SaveStrToFile(sPath, '[' + sData + ']', TEncoding.UTF8); // SaveJsonObjToFile(OA, sPath); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. SaveToFile()'); end; end; { TxEmpData } Constructor TxEmpData.Create; begin Inherited Create; DcData_ := TDictionary.Create; end; Destructor TxEmpData.Destroy; begin FreeAndNil(DcData_); Inherited; end; function TxEmpData.LoadFromFile(const sPath: String): Boolean; var O: ISuperObject; i: Integer; sKey: String; begin Result := false; try if Is_xEncrypt(sPath) then begin var sDecPath: String := GetRunExePathDir + 'Task\'; if ForceDirectories(sDecPath) then begin sDecPath := sDecPath + IntToStr(GetTickCount) + '_Emp.dat'; try if not Do_xDecrypt(sPath, sDecPath) then begin _Trace('Fail .. Do_xDecrypt() .. Path=%s', [sDecPath]); exit; end; if not LoadJsonObjFromFile(O, sDecPath) then begin _Trace('Fail .. TxEmpData.LoadJsonObjFromFile()'); exit; end; finally if FileExists(sDecPath) then DeleteFile(sDecPath); end; end else begin _Trace('Fail .. CreateDir() .. Path=%s', [sDecPath]); exit; end; end else if not LoadJsonObjFromFile(O, sPath) then begin _Trace('Fail .. TxEmpData.LoadJsonObjFromFile()'); exit; end; if (O.DataType <> stArray) or (O.AsArray.Length = 0) then begin _Trace('Fail .. TxEmpData.InvalidData()'); exit; end; for i := 0 to O.AsArray.Length - 1 do begin sKey := O.AsArray.O[i].S['empId'].ToUpper; try if sKey <> '' then DcData_.Add(sKey, O.AsArray.O[i].AsJSon); except _Trace('Fail .. TxEmpData.LoadFromFile() .. 중복 데이터? Key=%s', [sKey], 9); end; end; Result := true; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()'); end; end; procedure TxEmpData.UpdateData(const sJsonData: String); var O: ISuperObject; i: Integer; sKey: String; begin try O := SO(sJsonData); if O = nil then exit; if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then begin for i := 0 to O.A['created'].Length - 1 do begin sKey := O.A['created'].O[i].S['empId'].ToUpper; if not DcData_.ContainsKey(sKey) then begin DcData_.Add(sKey, O.A['created'].O[i].AsJSon); _Trace('emps.UpdateData() .. created, empId=%s', [O.A['created'].O[i].S['empId']], 5); end else begin DcData_[sKey] := O.A['created'].O[i].AsJSon; _Trace('emps.UpdateData() .. created(mod), empId=%s', [O.A['created'].O[i].S['empId']], 5); end; end; end; if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then begin for i := 0 to O.A['updated'].Length - 1 do begin sKey := O.A['updated'].O[i].S['empId'].ToUpper; if not DcData_.ContainsKey(sKey) then begin DcData_.Add(sKey, O.A['updated'].O[i].AsJSon); _Trace('emps.UpdateData() .. updated(new), empId=%s', [O.A['updated'].O[i].S['empId']], 5); end else begin DcData_[sKey] := O.A['updated'].O[i].AsJSon; _Trace('emps.UpdateData() .. updated, empId=%s', [O.A['updated'].O[i].S['empId']], 5); end; end; end; if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then begin for i := 0 to O.A['deleted'].Length - 1 do begin sKey := O.A['deleted'].O[i].S['empId'].ToUpper; if DcData_.ContainsKey(sKey) then begin DcData_.Remove(O.A['deleted'].O[i].S['empId'].ToUpper); _Trace('emps.UpdateData() .. deleted, empId=%s', [O.A['deleted'].O[i].S['empId']], 5); end; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. UpdateData()'); end; end; procedure TxEmpData.SaveToFile(const sPath: String); var enum: TEnumerator; sData, sEnt: String; begin try sData := ''; Guard(enum, DcData_.Values.GetEnumerator); while enum.MoveNext do begin sEnt := enum.Current; if sEnt <> '' then SumString(sData, sEnt, ','); end; SaveStrToFile(sPath, '[' + sData + ']', TEncoding.UTF8); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. SaveToFile()'); end; end; { TxPrtInfoData } Constructor TxPrtInfoData.Create; begin Inherited Create; DcData_ := TDictionary.Create; end; Destructor TxPrtInfoData.Destroy; begin FreeAndNil(DcData_); Inherited; end; function TxPrtInfoData.LoadFromFile(const sPath: String): Boolean; var O: ISuperObject; i: Integer; sKey: String; begin Result := false; try if Is_xEncrypt(sPath) then begin var sDecPath: String := GetRunExePathDir + 'Task\'; if ForceDirectories(sDecPath) then begin sDecPath := sDecPath + IntToStr(GetTickCount) + '_Prt.dat'; try if not Do_xDecrypt(sPath, sDecPath) then begin _Trace('Fail .. Do_xDecrypt() .. Path=%s', [sDecPath]); exit; end; if not LoadJsonObjFromFile(O, sDecPath) then begin _Trace('Fail .. TxPrtInfoData.LoadJsonObjFromFile()'); exit; end; finally if FileExists(sDecPath) then DeleteFile(sDecPath); end; end else begin _Trace('Fail .. CreateDir() .. Path=%s', [sDecPath]); exit; end; end else if not LoadJsonObjFromFile(O, sPath) then begin _Trace('Fail .. TxPrtInfoData.LoadJsonObjFromFile()'); exit; end; if (O.DataType <> stArray) or (O.AsArray.Length = 0) then begin _Trace('Fail .. TxPrtInfoData.InvalidData()'); exit; end; for i := 0 to O.AsArray.Length - 1 do begin sKey := O.AsArray.O[i].S['p_code'].ToUpper; try if sKey <> '' then DcData_.Add(sKey, O.AsArray.O[i].AsJSon); except _Trace('Fail .. xPrtInfoData.LoadFromFile() .. 중복 데이터? Key=%s', [sKey], 9); end; end; Result := true; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()'); end; end; procedure TxPrtInfoData.UpdateData(const sJsonData: String); var O: ISuperObject; i: Integer; sKey: String; begin try O := SO(sJsonData); if O = nil then exit; if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then begin for i := 0 to O.A['created'].Length - 1 do begin sKey := O.A['created'].O[i].S['p_code'].ToUpper; if not DcData_.ContainsKey(sKey) then begin DcData_.Add(sKey, O.A['created'].O[i].AsJSon); _Trace('xprint-printers.UpdateData() .. created, p_code=%s', [O.A['created'].O[i].S['p_code']], 5); end else begin DcData_[sKey] := O.A['created'].O[i].AsJSon; _Trace('xprint-printers.UpdateData() .. created(mod), p_code=%s', [O.A['created'].O[i].S['p_code']], 5); end; end; end; if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then begin for i := 0 to O.A['updated'].Length - 1 do begin sKey := O.A['updated'].O[i].S['p_code'].ToUpper; if not DcData_.ContainsKey(sKey) then begin DcData_.Add(sKey, O.A['updated'].O[i].AsJSon); _Trace('xprint-printers.UpdateData() .. updated(new), p_code=%s', [O.A['updated'].O[i].S['p_code']], 5); end else begin DcData_[sKey] := O.A['updated'].O[i].AsJSon; _Trace('xprint-printers.UpdateData() .. updated, p_code=%s', [O.A['updated'].O[i].S['p_code']], 5); end; end; end; if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then begin for i := 0 to O.A['deleted'].Length - 1 do begin sKey := O.A['deleted'].O[i].S['p_code'].ToUpper; if DcData_.ContainsKey(sKey) then begin DcData_.Remove(O.A['deleted'].O[i].S['p_code'].ToUpper); _Trace('xprint-printers.UpdateData() .. deleted, p_code=%s', [O.A['deleted'].O[i].S['p_code']], 5); end; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. UpdateData()'); end; end; procedure TxPrtInfoData.SaveToFile(const sPath: String); var enum: TEnumerator; sData, sEnt: String; begin try sData := ''; Guard(enum, DcData_.Values.GetEnumerator); while enum.MoveNext do begin sEnt := enum.Current; if sEnt <> '' then SumString(sData, sEnt, ','); end; SaveStrToFile(sPath, '[' + sData + ']', TEncoding.UTF8); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. SaveToFile()'); end; end; { TxStrData } Constructor TxStrData.Create(sName: String); begin Inherited Create; sName_ := sName; DataList_ := TStringList.Create; DataList_.CaseSensitive := false; end; Destructor TxStrData.Destroy; begin FreeAndNil(DataList_); Inherited; end; function TxStrData.LoadFromFile(const sPath: String): Boolean; var O: ISuperObject; i: Integer; sKey: String; begin try if Is_xEncrypt(sPath) then begin var sDecPath: String := GetRunExePathDir + 'Task\'; if ForceDirectories(sDecPath) then begin sDecPath := sDecPath + IntToStr(GetTickCount) + Format('_%s.dat', [sName_]); try if not Do_xDecrypt(sPath, sDecPath) then begin _Trace('Fail .. Do_xDecrypt() .. %s, Path=%s', [sName_, sDecPath]); exit; end; if not LoadJsonObjFromFile(O, sDecPath) then begin _Trace('Fail .. TxStrData.LoadJsonObjFromFile()-' + sName_); exit; end; finally if FileExists(sDecPath) then DeleteFile(sDecPath); end; end else begin _Trace('Fail .. CreateDir() .. %s, Path=%s', [sName_, sDecPath]); exit; end; end else if not LoadJsonObjFromFile(O, sPath) then begin _Trace('Fail .. TxStrData.LoadJsonObjFromFile()-' + sName_); exit; end; if (O.DataType <> stArray) or (O.AsArray.Length = 0) then exit; for i := 0 to O.AsArray.Length - 1 do DataList_.Add(O.AsArray.S[i]); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()'); end; end; procedure TxStrData.UpdateData(const sJsonData: String); var O: ISuperObject; i, n: Integer; sEnt: String; begin try O := SO(sJsonData); if O = nil then exit; if (O.O['created'] <> nil) and (O.O['created'].DataType = stArray) then begin for i := 0 to O.A['created'].Length - 1 do begin sEnt := O.A['created'].S[i]; if DataList_.IndexOf(sEnt) = -1 then begin DataList_.Add(sEnt); _Trace('%s.UpdateData() .. created, Ent=%s', [sName_, sEnt], 5); end; end; end; if (O.O['updated'] <> nil) and (O.O['updated'].DataType = stArray) then begin // 수정은 없을거 같지만... created와 똑같이 처리하는걸로 해준다 for i := 0 to O.A['updated'].Length - 1 do begin sEnt := O.A['updated'].S[i]; if DataList_.IndexOf(sEnt) = -1 then begin DataList_.Add(sEnt); _Trace('%s.UpdateData() .. updated, Ent=%s', [sName_, sEnt], 5); end; end; end; if (O.O['deleted'] <> nil) and (O.O['deleted'].DataType = stArray) then begin for i := 0 to O.A['deleted'].Length - 1 do begin sEnt := O.A['deleted'].S[i]; n := DataList_.IndexOf(sEnt); if n <> -1 then begin DataList_.Delete(n); _Trace('%s.UpdateData() .. deleted, Ent=%s', [sName_, sEnt], 5); end; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. UpdateData()'); end; end; procedure TxStrData.SaveToFile(const sPath: String); var OA: ISuperObject; i: Integer; begin try OA := TSuperObject.Create(stArray); for i := 0 to DataList_.Count - 1 do OA.AsArray.Add(DataList_[i]); SaveJsonObjToFile(OA, sPath); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. SaveToFile()'); end; end; function GetTimestampFromJsonStr(sJsonStr: String): String; var O: ISuperObject; begin Result := ''; try O := SO(sJsonStr); Result := O.S['timestamp']; except on E: Exception do ETgException.TraceException(E, 'Fail .. GetTimestampFromJsonStr(), Data=' + sJsonStr); end; end; procedure ProcessCheck_xPrintData(aHTTP: TIdHTTP); var ss: TStringStream; ReqPrtDatas: TxPrtDatas; sUpDt: String; begin try if CUSTOMER_TYPE <> CUSTOMER_KIMCHANG then exit; // 24시간에 한번만 업데이트 되도록 임시 보완 25_0924 14:55:13 kku // if (gMgSvc.dtOneDay_ <> 0) and (HoursBetween(gMgSvc.dtOneDay_, Now) < 24) then // exit; ReqPrtDatas := []; sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps/latest-timestamp')); if (sUpDt <> '') and (gMgSvc.EmpsUpDt <> sUpDt) then Include(ReqPrtDatas, xpdEmp); sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes/latest-timestamp')); if (sUpDt <> '') and (gMgSvc.BillUpDt <> sUpDt) then Include(ReqPrtDatas, xpdBill); sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers/latest-timestamp')); if (sUpDt <> '') and (gMgSvc.PrtsUpDt <> sUpDt) then Include(ReqPrtDatas, xpdPrts); sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes/latest-timestamp')); if (sUpDt <> '') and (gMgSvc.MkcdUpDt <> sUpDt) then Include(ReqPrtDatas, xpdMkcd); sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes/latest-timestamp')); if (sUpDt <> '') and (gMgSvc.LumpUpDt <> sUpDt) then Include(ReqPrtDatas, xpdLump); if ReqPrtDatas <> [] then ProcessRcv_xPrintData(aHTTP, ReqPrtDatas); except on E: Exception do ETgException.TraceException(E, 'Fail .. ProcessCheck_xPrintData()'); end; end; function ProcessRcv_xPrintData(aHTTP: TIdHTTP; aPrtDatas: TxPrtDatas; bForceDl: Boolean = false): Boolean; var sXPrtDir, sUpDt, sToDt, sPath: String; ss: TStringStream; bUpdate, bEncData: Boolean; procedure EncFile(const sPath: String); var sEncPath: String; begin if not bEncData then exit; if not FileExists(sPath) then exit; sEncPath := GetRunExePathDir + 'Task\'; if ForceDirectories(sEncPath) then begin sEncPath := sEncPath + '$xEnTmp.dat'; DeleteFile(sEncPath); if Do_xEncrypt(sPath, sEncPath) then begin DeleteFile(sPath); MoveFile_wait(sEncPath, sPath, 3); end; end; end; begin Result := false; try TTgTrace.T('ProcessRcv_xPrintData() ..', 1); sXPrtDir := GetCommonDataDir + 'bsoneprint\'; if not FileExists(sXPrtDir + EXE_xPrintSvc) then begin TTgTrace.T('Fail .. ProcessRcv_xPrintData() .. xPrint Client를 찾을 수 없음.', 1); exit; end; sXPrtDir := sXPrtDir + 'data\'; if not ForceDirectories(sXPrtDir) then begin TTgTrace.T('Fail .. ProcessRcv_xPrintData() .. data 폴더 생성 실패, Path=%s', [sXPrtDir], 1); exit; end; bEncData := true; try sPath := GetProgramFilesDir + DIR_TG + INI_FORCEHE; if FileExists(sPath) then begin var ini: TIniFile; Guard(ini, TIniFile.Create(sPath)); bEncData := not ini.ReadBool('Force', 'xPrintDataNoEnc', false); end; except // end; bUpdate := false; Guard(ss, TStringStream.Create('', TEncoding.UTF8)); if xpdEmp in aPrtDatas then begin sPath := sXPrtDir + 'xEmp.dat'; sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps/latest-timestamp')); if not bForceDl and FileExists(sPath) and (sUpDt <> '') then begin sToDt := '2099-12-31T23:59:59Z'; aHTTP.Get(gMgSvc.DestIPort + Format('aapi/emps?include=attribute&from=%s&to=%s&include=changeType&groupBy=changeType', [sUpDt, sToDt]), ss); end else aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps?include=attribute&isRetired=false&isDeleted=false', ss); // aHTTP.Get(gMgSvc.DestIPort + 'aapi/emps?include=attribute', ss); if ss.Size > 0 then begin if not bForceDl and FileExists(sPath) then begin var xEmpData: TxEmpData; Guard(xEmpData, TxEmpData.Create); xEmpData.LoadFromFile(sPath); xEmpData.UpdateData(ss.DataString); xEmpData.SaveToFile(sPath); TTgTrace.T('emps 데이터 업데이트 완료', 1); end else begin if bForceDl and FileExists(sPath) then DeleteFile(sPath); ss.SaveToFile(sPath); TTgTrace.T('emps 데이터 전체 다운로드 완료', 1); end; EncFile(sPath); end; if sUpDt <> '' then begin gMgSvc.EmpsUpDt := sUpDt; bUpdate := true; end; end; if xpdBill in aPrtDatas then begin sPath := sXPrtDir + 'xBil.dat'; ss.Clear; sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes/latest-timestamp')); if not bForceDl and FileExists(sPath) and (sUpDt <> '') then begin // 현재 PC 시간을 기준으로 하면 안됨 sToDt := '2099-12-31T23:59:59Z'; // sToDt := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss"Z"', ConvLocalToUtc(Now)); aHTTP.Get(gMgSvc.DestIPort + Format('aapi/billcodes?from=%s&to=%s&include=changeType&groupBy=changeType', [sUpDt, sToDt]), ss); end else aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes?isDeleted=false', ss); // aHTTP.Get(gMgSvc.DestIPort + 'aapi/billcodes', ss); if ss.Size > 0 then begin if not bForceDl and FileExists(sPath) then begin var xBillData: TxBillData; Guard(xBillData, TxBillData.Create); xBillData.LoadFromFile(sPath); xBillData.UpdateData(ss.DataString); xBillData.SaveToFile(sPath); TTgTrace.T('billcodes 데이터 업데이트 완료', 1); end else begin if bForceDl and FileExists(sPath) then DeleteFile(sPath); ss.SaveToFile(sPath); TTgTrace.T('billcodes 데이터 전체 다운로드 완료', 1); end; EncFile(sPath); end; if sUpDt <> '' then begin gMgSvc.BillUpDt := sUpDt; bUpdate := true; end; end; if xpdPrts in aPrtDatas then begin sPath := sXPrtDir + 'xPti.dat'; ss.Clear; sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers/latest-timestamp')); if not bForceDl and FileExists(sPath) and (sUpDt <> '') then begin // 현재 PC 시간을 기준으로 하면 안됨 sToDt := '2099-12-31T23:59:59Z'; // sToDt := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss"Z"', ConvLocalToUtc(Now)); aHTTP.Get(gMgSvc.DestIPort + Format('aapi/xprint-printers?from=%s&to=%s&include=changeType&groupBy=changeType', [sUpDt, sToDt]), ss); end else aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers?isDeleted=false', ss); // aHTTP.Get(gMgSvc.DestIPort + 'aapi/xprint-printers', ss); if ss.Size > 0 then begin if not bForceDl and FileExists(sPath) then begin var xPrtInfoData: TxPrtInfoData; Guard(xPrtInfoData, TxPrtInfoData.Create); xPrtInfoData.LoadFromFile(sPath); xPrtInfoData.UpdateData(ss.DataString); xPrtInfoData.SaveToFile(sPath); TTgTrace.T('xprint-printers 데이터 업데이트 완료', 1); end else begin if bForceDl and FileExists(sPath) then DeleteFile(sPath); ss.SaveToFile(sPath); TTgTrace.T('xprint-printers 데이터 전체 다운로드 완료', 1); end; EncFile(sPath); end; if sUpDt <> '' then begin gMgSvc.PrtsUpDt := sUpDt; bUpdate := true; end; end; if xpdMkcd in aPrtDatas then begin sPath := sXPrtDir + 'xMkc.dat'; ss.Clear; sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes/latest-timestamp')); if not bForceDl and FileExists(sPath) and (sUpDt <> '') then begin // 현재 PC 시간을 기준으로 하면 안됨 sToDt := '2099-12-31T23:59:59Z'; // sToDt := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss"Z"', ConvLocalToUtc(Now)); aHTTP.Get(gMgSvc.DestIPort + Format('aapi/mk-codes?from=%s&to=%s&include=changeType&groupBy=changeType', [sUpDt, sToDt]), ss); end else aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes?isDeleted=false', ss); // aHTTP.Get(gMgSvc.DestIPort + 'aapi/mk-codes', ss); if ss.Size > 0 then begin if not bForceDl and FileExists(sPath) then begin var xStrData: TxStrData; Guard(xStrData, TxStrData.Create('mk-codes')); xStrData.LoadFromFile(sPath); xStrData.UpdateData(ss.DataString); xStrData.SaveToFile(sPath); TTgTrace.T('mk-codes 데이터 업데이트 완료', 1); end else begin if bForceDl and FileExists(sPath) then DeleteFile(sPath); ss.SaveToFile(sXPrtDir + 'xMkc.dat'); TTgTrace.T('mk-codes 데이터 전체 다운로드 완료', 1); end; EncFile(sPath); end; if sUpDt <> '' then begin gMgSvc.MkcdUpDt := sUpDt; bUpdate := true; end; end; if xpdLump in aPrtDatas then begin sPath := sXPrtDir + 'xLum.dat'; ss.Clear; sUpDt := GetTimestampFromJsonStr(aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes/latest-timestamp')); if not bForceDl and FileExists(sPath) and (sUpDt <> '') then begin // 현재 PC 시간을 기준으로 하면 안됨 sToDt := '2099-12-31T23:59:59Z'; // sToDt := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss"Z"', ConvLocalToUtc(Now)); aHTTP.Get(gMgSvc.DestIPort + Format('aapi/lumpsum-fixed-codes?from=%s&to=%s&include=changeType&groupBy=changeType', [sUpDt, sToDt]), ss); end else aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes?isDeleted=false', ss); // aHTTP.Get(gMgSvc.DestIPort + 'aapi/lumpsum-fixed-codes', ss); if ss.Size > 0 then begin if not bForceDl and FileExists(sPath) then begin var xStrData: TxStrData; Guard(xStrData, TxStrData.Create('lumpsum-fixed-codes')); xStrData.LoadFromFile(sPath); xStrData.UpdateData(ss.DataString); xStrData.SaveToFile(sPath); TTgTrace.T('lumpsum-fixed-codes 데이터 업데이트 완료', 1); end else begin if bForceDl and FileExists(sPath) then DeleteFile(sPath); ss.SaveToFile(sPath); TTgTrace.T('lumpsum-fixed-codes 데이터 전체 다운로드 완료', 1); end; EncFile(sPath); end; if sUpDt <> '' then begin gMgSvc.LumpUpDt := sUpDt; bUpdate := true; end; end; if bUpdate then begin var ini: TIniFile; Guard(ini, TIniFile.Create(GetRunExePathDir + 'xPrint.ini')); ini.WriteString('DateTime', 'EmpsUpDt', gMgSvc.EmpsUpDt); ini.WriteString('DateTime', 'PrtsUpDt', gMgSvc.PrtsUpDt); ini.WriteString('DateTime', 'BillUpDt', gMgSvc.BillUpDt); ini.WriteString('DateTime', 'MkcdUpDt', gMgSvc.MkcdUpDt); ini.WriteString('DateTime', 'LumpUpDt', gMgSvc.LumpUpDt); gMgSvc.dtOneDay_ := Now; ini.WriteDateTime('DateTime', 'xOneDayDT', gMgSvc.dtOneDay_); end; Result := true; TTgTrace.T('ProcessRcv_xPrintData() .. OK', 1); except on E: Exception do ETgException.TraceException(E, 'Fail .. ProcessRcv_xPrintData()'); end; end; procedure CheckAndUpdate_xPrint; var sRes, sNewVer, sCurVer: String; NewVers, CurVers: TStringList; i: Integer; OVer: ISuperObject; bDoUpdate: Boolean; PO: TPrefModel; begin try if gMgSvc.ThdxPrintLog = nil then exit; PO := gMgSvc.PrefModel; if not PO.xPrintUpEnable then exit; sNewVer := PO.xPrintUpVer; if sNewVer = '' then exit; sCurVer := gMgSvc.xPrintVer; if sCurVer = '' then sCurVer := '1.0.0'; if sNewVer = sCurVer then exit; bDoUpdate := false; if not PO.xPrintUpFixedVer then begin Guard(NewVers, TStringList.Create); Guard(CurVers, TStringList.Create); if SplitString(sNewVer, '.', NewVers) = 0 then exit; if SplitString(sCurVer, '.', CurVers) = 0 then begin bDoUpdate := StrToIntDef(NewVers[0], 0) > StrToIntDef(sCurVer, 0); exit; end; for i := 0 to NewVers.Count - 1 do begin if i >= CurVers.Count then begin bDoUpdate := true; break; end; if StrToIntDef(NewVers[i], 0) < StrToIntDef(CurVers[i], 0) then break; if StrToIntDef(NewVers[i], 0) > StrToIntDef(CurVers[i], 0) then begin bDoUpdate := true; break; end; end; end else bDoUpdate := sNewVer <> sCurVer; if bDoUpdate then begin // 다운로드, 업데이트 실패해도 재시도 하지 않게 버전 정보 업데이트 25_0730 15:32:07 kku gMgSvc.xPrintVer := sNewVer; TTgTrace.T('xPrint 업데이트 시작 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]); var sUrl: String := gMgSvc.DestIPort + 'aapi/comps/xprint?ver=' + sNewVer; var nOldTO: Integer := gMgSvc.HTTP.ReadTimeout; var sPtPath: String := GetProgramFilesDir + DIR_TG; var sZName: String := 'x_patch.zip'; var fs: TFileStream := TFileStream.Create(sPtPath + sZName, fmCreate); gMgSvc.HTTP.ReadTimeout := 120000; try gMgSvc.HTTP.Get(sUrl, fs); Sleep(500); if FileExists(sPtPath + sZName) then begin FreeAndNil(fs); if GetFileSize_path(sPtPath + sZName) = 0 then begin TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 다운로드 실패, 크기 0'); DeleteFile(PChar(sPtPath + sZName)); exit; end; if not UninstallXPrt(true) then begin gMgSvc.xPrintVer := sCurVer; TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 제거 실패.'); exit; end; var sXPrtPath: String := 'C:\ProgramData\bsoneprint\'; if ForceDirectories(sXPrtPath) then begin TZipFile.ExtractZipFile(sPtPath + sZName, sXPrtPath); DeleteFile(PChar(sPtPath + sZName)); ExecutePath_hide(sXprtPath + EXE_xPrintSvc, '-install'); end; end; finally if fs <> nil then FreeAndNil(fs); gMgSvc.HTTP.ReadTimeout := nOldTO; end; TTgTrace.T('xPrint 업데이트 완료 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]); end; except on E: Exception do ETgException.TraceException(E, 'Fail .. CheckAndUpdate_xPrint()'); end; end; //procedure CheckAndUpdate_xPrint; //var // sRes, // sNewVer, // sCurVer: String; // NewVers, // CurVers: TStringList; // i: Integer; // OVer: ISuperObject; // bDoUpdate: Boolean; //begin // try // if gMgSvc.ThdxPrintLog = nil then // exit; // // sRes := gMgSvc.HTTP.Get(gMgSvc.DestIPort + 'aapi/comps/xprint/info'); // if sRes = '' then // exit; // try // OVer := SO(sRes); // except // exit; // end; // // sNewVer := OVer.S['ver']; // if sNewVer = '' then // exit; // // sCurVer := gMgSvc.xPrintVer; // if sCurVer = '' then // sCurVer := '1.0.0'; // // if sNewVer = sCurVer then // exit; // // Guard(NewVers, TStringList.Create); // Guard(CurVers, TStringList.Create); // if SplitString(sNewVer, '.', NewVers) = 0 then // exit; // // bDoUpdate := false; // if SplitString(sCurVer, '.', CurVers) = 0 then // begin // bDoUpdate := StrToIntDef(NewVers[0], 0) > StrToIntDef(sCurVer, 0); // exit; // end; // // for i := 0 to NewVers.Count - 1 do // begin // if i >= CurVers.Count then // begin // bDoUpdate := true; // break; // end; // // if StrToIntDef(NewVers[i], 0) < StrToIntDef(CurVers[i], 0) then // break; // // if StrToIntDef(NewVers[i], 0) > StrToIntDef(CurVers[i], 0) then // begin // bDoUpdate := true; // break; // end; // end; // // if bDoUpdate then // begin // // 다운로드, 업데이트 실패해도 재시도 하지 않게 버전 정보 업데이트 25_0730 15:32:07 kku // gMgSvc.xPrintVer := sNewVer; // TTgTrace.T('xPrint 업데이트 시작 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]); // // var sUrl: String := gMgSvc.DestIPort + 'aapi/comps/xprint'; // var nOldTO: Integer := gMgSvc.HTTP.ReadTimeout; // var sPtPath: String := GetProgramFilesDir + DIR_TG; // var sZName: String := 'x_patch.zip'; // var fs: TFileStream := TFileStream.Create(sPtPath + sZName, fmCreate); // gMgSvc.HTTP.ReadTimeout := 120000; // try // gMgSvc.HTTP.Get(sUrl, fs); // Sleep(500); // if FileExists(sPtPath + sZName) then // begin // FreeAndNil(fs); // if GetFileSize_path(sPtPath + sZName) = 0 then // begin // TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 다운로드 실패, 크기 0'); // DeleteFile(PChar(sPtPath + sZName)); // exit; // end; // // if not UninstallXPrt(true) then // begin // gMgSvc.xPrintVer := sCurVer; // TTgTrace.T('Fail .. CheckAndUpdate_xPrint() .. 제거 실패.'); // exit; // end; // // var sXPrtPath: String := 'C:\ProgramData\bsoneprint\'; // if ForceDirectories(sXPrtPath) then // begin // TZipFile.ExtractZipFile(sPtPath + sZName, sXPrtPath); // DeleteFile(PChar(sPtPath + sZName)); // // ExecutePath_hide(sXprtPath + EXE_xPrintSvc, '-install'); // end; // end; // finally // if fs <> nil then // FreeAndNil(fs); // gMgSvc.HTTP.ReadTimeout := nOldTO; // end; // // TTgTrace.T('xPrint 업데이트 완료 .. Ver=%s, NewVer=%s', [sCurVer, sNewVer]); // end; // except // on E: Exception do // ETgException.TraceException(E, 'Fail .. CheckAndUpdate_xPrint()'); // end; //end; end.