{*******************************************************} { } { ManagerPrint } { } { Copyright (C) 2024 kku } { } {*******************************************************} unit ManagerPrint; interface uses Tocsg.Obj, System.SysUtils, System.Generics.Collections, Tocsg.Printer, Winapi.Windows, CttSchDefine, System.SyncObjs, System.Classes; const DAT_PRINTINFO = 'pinfo.dat'; PASS_PRINTINFO = '2S=Z0WM\B<5h_X*F'; // PASS_EMFZIP = '251014ToCSG-bs1'; type PPrtEnt = ^TPrtEnt; TPrtEnt = record dtReg, dtAprv: TDateTime; sId, sText, sOcrText, sVioText, sThumbIds, sPName, sFPath: String; WInfo: TPrtWaterEnt; bPostApv: Boolean; end; TPrtEntList = TList; TManagerPrint = class(TTgObject) private CS_: TCriticalSection; sDataDir_: String; EntList_: TPrtEntList; dwChkTick_: DWORD; procedure Lock; procedure Unlock; procedure OnEntNotify(Sender: TObject; const Item: PPrtEnt; Action: TCollectionNotification); public Constructor Create; Destructor Destroy; override; function AddPrintInfo(PrtInfo: TPrtJobDevInfo; sPName, sFPath, sSpoolPath, sEmfDir, sPortInfo, sText, sOcrText, sVioText, sThumbIds: String; bPostApv: Boolean): PPrtEnt; function GetPrintInfo(sId: String): PPrtEnt; function DelPrintInfo(sId: String; bSave: Boolean = false): PPrtEnt; function GetEnts: TEnumerator; procedure Save(bLock: Boolean = true); procedure Load; procedure ProcessExpired; property DataDir: String read sDataDir_; end; implementation uses Tocsg.Exception, Tocsg.Strings, ManagerService, Tocsg.Path, Tocsg.Files, superobject, Tocsg.Json, Tocsg.Convert, Tocsg.DRM.Encrypt, GlobalDefine, Condition, ManagerModel, Tocsg.Safe, System.DateUtils, System.Zip; { TManagerPrint } Constructor TManagerPrint.Create; begin Inherited Create; dwChkTick_ := 0; CS_ := TCriticalSection.Create; sDataDir_ := GetRunExePathDir + 'Data\Print\'; EntList_ := TPrtEntList.Create; EntList_.OnNotify := OnEntNotify; Load; end; Destructor TManagerPrint.Destroy; begin FreeAndNil(EntList_); Inherited; FreeAndNil(CS_); end; procedure TManagerPrint.Lock; begin CS_.Acquire; end; procedure TManagerPrint.Unlock; begin CS_.Release; end; procedure TManagerPrint.OnEntNotify(Sender: TObject; const Item: PPrtEnt; Action: TCollectionNotification); begin if Action = cnRemoved then Dispose(Item); end; function TManagerPrint.AddPrintInfo(PrtInfo: TPrtJobDevInfo; sPName, sFPath, sSpoolPath, sEmfDir, sPortInfo, sText, sOcrText, sVioText, sThumbIds: String; bPostApv: Boolean): PPrtEnt; var sId, sPath, sDept: String; pEnt: PPrtEnt; enc: TTgDrmEnc; PO: TPrefModel; bResult: Boolean; begin Result := nil; try sId := GetGUID; {$IFDEF DEUBG} ASSERT(sId <> ''); sId := UpperCase(sId); {$ELSE} if sId = '' then sId := FormatDateTime('yyyymmddhhnnss+', Now) + gMgSvc.EmpNo else sId := UpperCase(sId); {$ENDIF} bResult := false; // sPath := sDataDir_ + sId + '.pdh'; // if ForceDirectories(sDataDir_) then // begin // // 스풀파일 암호화 후 저장 24_0924 14:54:14 kku // enc := TTgDrmEnc.Create(sPath); // try // PO := gMgSvc.PrefModel; // sDept := gMgSvc.DeptName; // if sDept = '' then // sDept := PO.DeptName; // // enc.SetHaed(PASS_DRM_HEAD, SIG_DRM, gMgSvc.EmpNo, gMgSvc.UserName, // sDept, PO.PolicyName, CUSTOMER_TYPE); // bResult := enc.EncryptFromFile(GetMK + '&PtRh', CutFileExt(sSpoolPath) + '.shd'); // finally // FreeAndNil(enc); // end; // end; sPath := sDataDir_ + sId + '.pdt'; if ForceDirectories(sDataDir_) then begin // 스풀파일 암호화 후 저장 24_0924 14:54:14 kku enc := TTgDrmEnc.Create(sPath); try PO := gMgSvc.PrefModel; sDept := gMgSvc.DeptName; if sDept = '' then sDept := PO.DeptName; enc.SetHaed(PASS_DRM_HEAD, SIG_DRM, gMgSvc.EmpNo, gMgSvc.UserName, sDept, PO.PolicyName, CUSTOMER_TYPE); bResult := enc.EncryptFromFile(GetMK + '&PtR', sSpoolPath); finally FreeAndNil(enc); end; if DirectoryExists(sEmfDir) then begin var EmfList: TStringList; Guard(EmfList, TStringList.Create); ExtrFilesFromDir(sEmfDir, EmfList, false, 'em1'); if EmfList.Count > 0 then begin sPath := sDataDir_ + sId + '.dat'; var zip: TZipFile; Guard(zip, TZipFile.Create); zip.Open(sPath, zmWrite); zip.UTF8Support := true; var i: Integer; for i := 0 to EmfList.Count - 1 do zip.Add(sEmfDir + EmfList[i]); end; end; end; if bResult then begin New(pEnt); ZeroMemory(pEnt, SizeOf(TPrtEnt)); pEnt.dtReg := Now; pEnt.sId := sId; pEnt.sText := sText; pEnt.sOcrText := sOcrText; pEnt.sVioText := sVioText; pEnt.sThumbIds := sThumbIds; pEnt.sPName := sPName; pEnt.sFPath := sFPath; pEnt.bPostApv := bPostApv; pEnt.WInfo.sPtrName := PrtInfo.sPtrName; pEnt.WInfo.sDocName := PrtInfo.sDocName; pEnt.WInfo.DevMode := TTgRtti.SetTypeToStr(PrtInfo.DevMode); pEnt.WInfo.dwCopy := PrtInfo.dwCopyCount; pEnt.WInfo.dwTotalPage := PrtInfo.dwTotalPage; pEnt.WInfo.bPaperV := PrtInfo.bPaperV; pEnt.WInfo.bColor := PrtInfo.bColor; pEnt.WInfo.sPaperInfo := PrtInfo.sPaperInfo; pEnt.WInfo.sPrtIp := PrinterDriverToIP(PrtInfo.sDrvName); pEnt.WInfo.sPdfPath := sPortInfo; pEnt.WInfo.bUseWM := true; Lock; try EntList_.Add(pEnt); finally Unlock; end; Result := pEnt; Save; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. AddPrintInfo()'); end; end; function TManagerPrint.GetPrintInfo(sId: String): PPrtEnt; var i: Integer; begin Result := nil; try Lock; try for i := 0 to EntList_.Count - 1 do begin if EntList_[i].sId = sId then begin Result := EntList_[i]; exit; end; end; finally Unlock; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. GetPrintInfo()'); end; end; function TManagerPrint.DelPrintInfo(sId: String; bSave: Boolean = false): PPrtEnt; var i: Integer; begin Result := nil; try Lock; try for i := 0 to EntList_.Count - 1 do begin if EntList_[i].sId = sId then begin DeleteFile_wait(sDataDir_ + sId + '.pdt'); DeleteFile_wait(sDataDir_ + sId + '.dat'); DeleteDir(sDataDir_ + sId); // DeleteFile_wait(sDataDir_ + sId + '.pdh'); EntList_.Delete(i); if bSave then Save(false); exit; end; end; finally Unlock; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DelPrintInfo()'); end; end; function TManagerPrint.GetEnts: TEnumerator; begin Lock; try Result := EntList_.GetEnumerator; finally Unlock; end; end; procedure TManagerPrint.Save(bLock: Boolean = true); var O, OA: ISuperObject; i: Integer; begin try OA := TSuperObject.Create(stArray); if bLock then Lock; try for i := 0 to EntList_.Count - 1 do OA.AsArray.Add(TTgJson.ValueToJsonObject(EntList_[i]^)); finally if bLock then Unlock; end; O := SO; O.O['List'] := OA; SaveJsonObjToEncFile(O, sDataDir_ + DAT_PRINTINFO, PASS_PRINTINFO); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. Save()'); end; end; procedure TManagerPrint.Load; var O: ISuperObject; i: Integer; Ent: TPrtEnt; pEnt: PPrtEnt; begin try EntList_.Clear; if LoadJsonObjFromEncFile(O, sDataDir_ + DAT_PRINTINFO, PASS_PRINTINFO) then begin if O.O['List'] = nil then exit; if O.O['List'].DataType <> stArray then exit; if O.A['List'].Length > 0 then begin for i := 0 to O.A['List'].Length - 1 do begin // Ent := TTgJSon.GetDataAsType(O.A['List'][i]); Ent.dtReg := JavaToDelphiDateTime(O.A['List'][i].I['dtReg']); Ent.dtAprv := JavaToDelphiDateTime(O.A['List'][i].I['dtAprv']); Ent.sId := O.A['List'][i].S['sId']; Ent.sText := O.A['List'][i].S['sText']; Ent.sOcrText := O.A['List'][i].S['sOcrText']; Ent.sVioText := O.A['List'][i].S['sVioText']; Ent.sThumbIds := O.A['List'][i].S['sThumbIds']; Ent.sPName := O.A['List'][i].S['sPName']; Ent.sFPath := O.A['List'][i].S['sFPath']; if O.A['List'][i].O['WInfo'] <> nil then Ent.WInfo := TTgJSon.GetDataAsType(O.A['List'][i].O['WInfo']); Ent.bPostApv := O.A['List'][i].B['bPostApv']; if FileExists(sDataDir_ + Ent.sId + '.pdt') then begin New(pEnt); pEnt^ := Ent; EntList_.Add(pEnt); end; end; end else begin DeleteDirSub(sDataDir_); end; Save; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. Load()'); end; end; procedure TManagerPrint.ProcessExpired; var enum: TEnumerator; dtNow: TDateTime; pEnt: PPrtEnt; bMoveNext, bUpdate: Boolean; i: Integer; begin try // 1시간에 한번만 처리 if (dwChkTick_ <> 0) and ( (GetTickCount - dwChkTick_) < 600000 ) then exit; dwChkTick_ := GetTickCount; bUpdate := false; dtNow := Now; Guard(enum, GetEnts); bMoveNext := enum.MoveNext; Lock; try while bMoveNext do begin pEnt := enum.Current; if pEnt = nil then break; bMoveNext := enum.MoveNext; // 승인 후 24시간 이후면 제거 if (pEnt.dtAprv <> 0) and (HoursBetween(pEnt.dtAprv, dtNow) >= 24) then begin i := EntList_.IndexOf(pEnt); if i <> -1 then begin EntList_.Delete(i); bUpdate := true; end; continue; end; // 요청 후 30시간 이후면 제거 if HoursBetween(pEnt.dtReg, dtNow) >= 30 then begin i := EntList_.IndexOf(pEnt); if i <> -1 then begin EntList_.Delete(i); bUpdate := true; end; end; end; if bUpdate then Save(false); finally Unlock; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. ProcessExpired()'); end; end; end.