601 lines
17 KiB
Plaintext
601 lines
17 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.Packet }
|
|
{ }
|
|
{ Copyright (C) 2022 kku }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.Packet;
|
|
|
|
interface
|
|
|
|
uses
|
|
Tocsg.Obj, Tocsg.Exception, System.SysUtils, Winapi.Windows,
|
|
superobject, System.Classes;
|
|
|
|
const
|
|
SIZE_INTEGER = SizeOf(Integer);
|
|
CTX_PACKET_SIGNATURE: AnsiString = '@OC$.G';
|
|
LEN_CTX_PACKET_SIGNATURE = 6;
|
|
|
|
type
|
|
// Server -> Client
|
|
PCtxPacketHeader = ^TCtxPacketHeader;
|
|
TCtxPacketHeader = packed record
|
|
sSig: array [0..5] of AnsiChar; // #SPK.$$
|
|
wRank: WORD;
|
|
dwId,
|
|
dwSize: DWORD;
|
|
end;
|
|
|
|
|
|
// 종류 추가 되면 패킷 해더의 wRank 수정해야함
|
|
TTgPacketKind = (pkNormal, pkFileQueue, pkIgnore, pkCritical);
|
|
TTgPacketHeader = record
|
|
Cmd,
|
|
Result: Integer;
|
|
Toss,
|
|
Handle,
|
|
WndMessage: LONGLONG;
|
|
ResultMsg: String;
|
|
PacketKind: TTgPacketKind;
|
|
end;
|
|
|
|
TSnTextEncoding = System.SysUtils.TEncoding;
|
|
TSnBytes = TBytes;
|
|
|
|
ETgPacket = class(ETgException);
|
|
ITgPacket = interface
|
|
['{5F9E8D1B-7371-41D2-AA7A-E8DDAE3788B9}']
|
|
function _GetPacketHeader: TTgPacketHeader;
|
|
function _GetJsonObject: ISuperObject;
|
|
|
|
function ToJsonString: String;
|
|
function ToBytes(var SnBytes: TSnBytes): Integer;
|
|
function ToBytesDataOnly(var SnBytes: TSnBytes): Integer;
|
|
function SaveToFile(sPath: String): Boolean;
|
|
end;
|
|
|
|
ISendPacket = interface(ITgPacket)
|
|
['{0322E57A-C699-40BE-B0DF-64B9A69A5701}']
|
|
function GetCommand: Integer;
|
|
procedure SetPacketKind(aPacketKind: TTgPacketKind);
|
|
function GetPacketKind: TTgPacketKind;
|
|
procedure SetHandle(llHandle: LONGLONG);
|
|
procedure SetWndMessage(llWndMessage: LONGLONG);
|
|
procedure SetToss(llToss: LONGLONG);
|
|
procedure SetResult(nResult: Integer);
|
|
procedure SetResultMsg(const sResultMsg: String);
|
|
function GetResult: Integer;
|
|
function GetResultMsg: String;
|
|
function GetSocket: TObject;
|
|
procedure SetSocket(aSocket: TObject);
|
|
|
|
function GetO(const sPath: String): ISuperObject;
|
|
|
|
procedure PutO(const sPath: String; const Value: ISuperObject);
|
|
procedure PutB(const sPath: String; Value: Boolean);
|
|
procedure PutI(const sPath: String; Value: SuperInt);
|
|
procedure PutC(const sPath: String; Value: Currency);
|
|
procedure PutD(const sPath: String; Value: Double);
|
|
procedure PutS(const sPath: String; const Value: String);
|
|
|
|
property Command: Integer read GetCommand;
|
|
property Handle: LONGLONG write SetHandle;
|
|
property WndMessage: LONGLONG write SetWndMessage;
|
|
property Toss: LONGLONG write SetToss;
|
|
property Result: Integer read GetResult write SetResult;
|
|
property ResultMsg: String read GetResultMsg write SetResultMsg;
|
|
property PacketKind: TTgPacketKind read GetPacketKind write SetPacketKind;
|
|
property Socket: TObject read GetSocket write SetSocket;
|
|
|
|
property O[const sPath: String]: ISuperObject read GetO write PutO; default;
|
|
property B[const sPath: String]: Boolean write PutB;
|
|
property I[const sPath: String]: SuperInt write PutI;
|
|
property D[const sPath: String]: Double write PutD;
|
|
property C[const sPath: String]: Currency write PutC;
|
|
property S[const sPath: String]: String write PutS;
|
|
end;
|
|
|
|
IRcvPacket = interface(ITgPacket)
|
|
['{C1BFCE0F-1B34-4FCC-84AC-4F24CA6D72A5}']
|
|
function GetCommand: Integer;
|
|
function GetPacketKind: TTgPacketKind;
|
|
function GetHandle: LONGLONG;
|
|
function GetWndMessage: LONGLONG;
|
|
function GetToss: LONGLONG;
|
|
function GetResult: Integer;
|
|
function GetResultMsg: String;
|
|
function GetSocket: TObject;
|
|
function GetRcvPacketSize: DWORD;
|
|
|
|
function ToJsonString: String;
|
|
|
|
function GetO(const sPath: String): ISuperObject;
|
|
function GetB(const sPath: String): Boolean;
|
|
function GetI(const sPath: String): SuperInt;
|
|
function GetD(const sPath: String): Double;
|
|
function GetC(const sPath: String): Currency;
|
|
function GetS(const sPath: String): String;
|
|
function GetA(const sPath: String): TSuperArray;
|
|
|
|
property Command: Integer read GetCommand;
|
|
property PacketKind: TTgPacketKind read GetPacketKind;
|
|
property Handle: LONGLONG read GetHandle;
|
|
property WndMessage: LONGLONG read GetWndMessage;
|
|
property Toss: LONGLONG read GetToss;
|
|
property Result: Integer read GetResult;
|
|
property ResultMsg: String read GetResultMsg;
|
|
property Socket: TObject read GetSocket;
|
|
property RcvPacketSize: DWORD read GetRcvPacketSize;
|
|
|
|
property O[const sPath: String]: ISuperObject read GetO; default;
|
|
property B[const sPath: String]: Boolean read GetB;
|
|
property I[const sPath: String]: SuperInt read GetI;
|
|
property D[const sPath: String]: Double read GetD;
|
|
property C[const sPath: String]: Currency read GetC;
|
|
property S[const sPath: String]: String read GetS;
|
|
property A[const sPath: String]: TSuperArray read GetA;
|
|
end;
|
|
|
|
TTgPacket = class(TInterfacedObject, ITgPacket, ISendPacket, IRcvPacket)
|
|
protected
|
|
Socket_: TObject;
|
|
PacketHeader_: TTgPacketHeader;
|
|
SuperObject_: ISuperObject;
|
|
dwRcvLen_: DWORD;
|
|
|
|
function _GetPacketHeader: TTgPacketHeader;
|
|
function _GetJsonObject: ISuperObject;
|
|
|
|
procedure PutO(const sPath: String; const Value: ISuperObject);
|
|
procedure PutB(const sPath: String; Value: Boolean);
|
|
procedure PutI(const sPath: String; Value: SuperInt);
|
|
procedure PutC(const sPath: String; Value: Currency);
|
|
procedure PutD(const sPath: String; Value: Double);
|
|
procedure PutS(const sPath: String; const Value: String);
|
|
|
|
function GetO(const sPath: String): ISuperObject;
|
|
function GetB(const sPath: String): Boolean;
|
|
function GetI(const sPath: String): SuperInt;
|
|
function GetD(const sPath: String): Double;
|
|
function GetC(const sPath: String): Currency;
|
|
function GetS(const sPath: String): String;
|
|
function GetA(const sPath: String): TSuperArray;
|
|
|
|
function GetCommand: Integer;
|
|
procedure SetPacketKind(aPacketKind: TTgPacketKind);
|
|
function GetPacketKind: TTgPacketKind;
|
|
procedure SetHandle(llHandle: LONGLONG);
|
|
function GetHandle: LONGLONG;
|
|
procedure SetWndMessage(llWndMessage: LONGLONG);
|
|
function GetWndMessage: LONGLONG;
|
|
procedure SetToss(llToss: LONGLONG);
|
|
function GetToss: LONGLONG;
|
|
procedure SetResult(nResult: Integer);
|
|
function GetResult: Integer;
|
|
procedure SetResultMsg(const sResultMsg: String);
|
|
function GetResultMsg: String;
|
|
function GetSocket: TObject;
|
|
procedure SetSocket(aSocket: TObject);
|
|
function GetRcvPacketSize: DWORD; // for IRcvPacket
|
|
public
|
|
Constructor Create; overload;
|
|
Constructor Create(const aCmd: Integer; PacketKind: TTgPacketKind = pkNormal); overload;
|
|
Constructor Create(aPacket: ITgPacket; PacketKind: TTgPacketKind = pkNormal); overload;
|
|
Constructor Create(const aRcvData: Pointer; nRcvLen: Integer); overload;
|
|
Constructor Create(const aRcvData: TSnBytes; bIncludeLen: Boolean = false; aSocket: TObject= nil{for ClientContext}); overload;
|
|
Constructor Create(aSocket: TObject{for ClientContext}; const aRcvData: Pointer; nRcvLen: Integer); overload;
|
|
Constructor Create(const sJsonData: String); overload;
|
|
function ToJsonString: String;
|
|
function ToBytes(var SnBytes: TSnBytes): Integer;
|
|
function ToBytesDataOnly(var SnBytes: TSnBytes): Integer;
|
|
function SaveToFile(sPath: String): Boolean;
|
|
|
|
property Command: Integer read GetCommand;
|
|
property PacketKind: TTgPacketKind read GetPacketKind;
|
|
property Toss: LONGLONG read GetToss write SetToss;
|
|
property Handle: LONGLONG read GetHandle write SetHandle;
|
|
property WndMessage: LONGLONG read GetWndMessage write SetWndMessage;
|
|
property Result: Integer read GetResult write SetResult;
|
|
property ResultMsg: String read GetResultMsg write SetResultMsg;
|
|
property Socket: TObject read GetSocket write SetSocket;
|
|
|
|
property O[const sPath: String]: ISuperObject read GetO write PutO; default;
|
|
property B[const sPath: String]: Boolean read GetB write PutB;
|
|
property I[const sPath: String]: SuperInt read GetI write PutI;
|
|
property D[const sPath: String]: Double read GetD write PutD;
|
|
property C[const sPath: String]: Currency read GetC write PutC;
|
|
property S[const sPath: String]: String read GetS write PutS;
|
|
end;
|
|
|
|
const
|
|
LEN_CTX_PACKET_HEADER = SizeOf(TCtxPacketHeader);
|
|
BUFFER_SIZE = 32 * 1024;
|
|
MAX_BUF_LEN = BUFFER_SIZE;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Tocsg.Safe, Tocsg.JSON;
|
|
|
|
{ TTgPacket }
|
|
|
|
Constructor TTgPacket.Create;
|
|
begin
|
|
Inherited Create;
|
|
ZeroMemory(@PacketHeader_, SizeOf(PacketHeader_));
|
|
dwRcvLen_ := 0;
|
|
end;
|
|
|
|
Constructor TTgPacket.Create(const aCmd: Integer; PacketKind: TTgPacketKind = pkNormal);
|
|
begin
|
|
Create;
|
|
PacketHeader_.Cmd := aCmd;
|
|
PacketHeader_.PacketKind := PacketKind;
|
|
SuperObject_ := TSuperObject.Create;
|
|
end;
|
|
|
|
Constructor TTgPacket.Create(aPacket: ITgPacket; PacketKind: TTgPacketKind = pkNormal);
|
|
begin
|
|
Create;
|
|
PacketHeader_ := aPacket._GetPacketHeader;
|
|
SuperObject_ := aPacket._GetJsonObject;
|
|
PacketHeader_.PacketKind := PacketKind;
|
|
end;
|
|
|
|
Constructor TTgPacket.Create(const aRcvData: TSnBytes; bIncludeLen: Boolean = false; aSocket: TObject = nil{for ClientContext});
|
|
|
|
procedure ExtractData;
|
|
var
|
|
nDataLen: Integer;
|
|
sJsonData: UTF8String;
|
|
begin
|
|
nDataLen := 0;
|
|
|
|
if bIncludeLen then
|
|
begin
|
|
dwRcvLen_ := Length(aRcvData);
|
|
if dwRcvLen_ < 4 then
|
|
raise ETgPacket.Create('Rcv 버퍼가 손상되었습니다.');
|
|
|
|
CopyMemory(@nDataLen, @aRcvData[0], SIZE_INTEGER);
|
|
|
|
if nDataLen <> (dwRcvLen_ - SIZE_INTEGER) then
|
|
begin
|
|
raise ETgPacket.CreateFmt('Rcv 데이터 크기가 잘못되었습니다. (DataLen = %d, RcvBufLen = %d',
|
|
[nDataLen, dwRcvLen_ - SIZE_INTEGER]);
|
|
end;
|
|
|
|
SetLength(sJsonData, nDataLen);
|
|
CopyMemory(@sJsonData[1], @aRcvData[4], nDataLen);
|
|
end else begin
|
|
nDataLen := Length(aRcvData);
|
|
dwRcvLen_ := nDataLen;
|
|
SetLength(sJsonData, nDataLen);
|
|
CopyMemory(@sJsonData[1], @aRcvData[0], nDataLen);
|
|
end;
|
|
|
|
SuperObject_ := SO(sJsonData);
|
|
|
|
try
|
|
with SuperObject_['Header'], PacketHeader_ do
|
|
begin
|
|
Cmd := I['Cmd'];
|
|
Handle := I['Handle'];
|
|
WndMessage := I['WndMessage'];
|
|
PacketKind := TTgPacketKind(I['PacketKind']);
|
|
Result := I['Result'];
|
|
Toss := I['Toss'];
|
|
ResultMsg := S['ResultMsg'];
|
|
end;
|
|
except
|
|
raise ETgPacket.Create('Invalid packet ..');
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Create;
|
|
Socket_ := aSocket;
|
|
ExtractData;
|
|
end;
|
|
|
|
Constructor TTgPacket.Create(aSocket: TObject{for ClientContext}; const aRcvData: Pointer; nRcvLen: Integer);
|
|
begin
|
|
Create(aRcvData, nRcvLen);
|
|
Socket_ := aSocket;
|
|
end;
|
|
|
|
Constructor TTgPacket.Create(const aRcvData: Pointer; nRcvLen: Integer);
|
|
|
|
procedure ExtractData;
|
|
var
|
|
sJsonData: UTF8String;
|
|
begin
|
|
dwRcvLen_ := nRcvLen;
|
|
SetLength(sJsonData, nRcvLen);
|
|
CopyMemory(@sJsonData[1], aRcvData, nRcvLen);
|
|
|
|
SuperObject_ := SO(sJsonData);
|
|
|
|
try
|
|
with SuperObject_['Header'], PacketHeader_ do
|
|
begin
|
|
Cmd := I['Cmd'];
|
|
Handle := I['Handle'];
|
|
WndMessage := I['WndMessage'];
|
|
PacketKind := TTgPacketKind(I['PacketKind']);
|
|
Result := I['Result'];
|
|
Toss := I['Toss'];
|
|
ResultMsg := S['ResultMsg'];
|
|
end;
|
|
except
|
|
raise ETgPacket.Create('Invalid packet ..');
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Create;
|
|
ExtractData;
|
|
end;
|
|
|
|
Constructor TTgPacket.Create(const sJsonData: String);
|
|
begin
|
|
Inherited Create;
|
|
SuperObject_ := SO(sJsonData);
|
|
with SuperObject_['Header'], PacketHeader_ do
|
|
begin
|
|
Cmd := I['Cmd'];
|
|
Handle := I['Handle'];
|
|
WndMessage := I['WndMessage'];
|
|
PacketKind := TTgPacketKind(I['PacketKind']);
|
|
Result := I['Result'];
|
|
Toss := I['Toss'];
|
|
ResultMsg := S['ResultMsg'];
|
|
end;
|
|
end;
|
|
|
|
function TTgPacket._GetPacketHeader: TTgPacketHeader;
|
|
begin
|
|
Result := PacketHeader_;
|
|
end;
|
|
|
|
function TTgPacket._GetJsonObject: ISuperObject;
|
|
begin
|
|
Result := SuperObject_;
|
|
end;
|
|
|
|
function TTgPacket.ToJsonString: String;
|
|
var
|
|
O: ISuperObject;
|
|
begin
|
|
Result := '';
|
|
if SuperObject_ <> nil then
|
|
begin
|
|
O := SO;
|
|
with PacketHeader_, O do
|
|
begin
|
|
I['Cmd'] := Cmd;
|
|
if Handle <> 0 then
|
|
I['Handle'] := Handle;
|
|
if WndMessage <> 0 then
|
|
I['WndMessage'] := WndMessage;
|
|
if PacketKind <> pkNormal then
|
|
I['PacketKind'] := Integer(PacketKind);
|
|
if Result <> 0 then
|
|
I['Result'] := Result;
|
|
if Toss <> 0 then
|
|
I['Toss'] := Toss;
|
|
if ResultMsg <> '' then
|
|
S['ResultMsg'] := ResultMsg;
|
|
end;
|
|
SuperObject_.O['Header'] := O;
|
|
Result := SuperObject_.AsJSon;
|
|
end;
|
|
end;
|
|
|
|
function TTgPacket.ToBytes(var SnBytes: TSnBytes): Integer;
|
|
var
|
|
sJsonData: UTF8String;
|
|
nDataLen: Integer;
|
|
begin
|
|
Result := 0;
|
|
sJsonData := UTF8Encode(ToJsonString);
|
|
if sJsonData <> '' then
|
|
begin
|
|
nDataLen := Length(sJsonData);
|
|
Result := SIZE_INTEGER + Length(sJsonData);
|
|
SetLength(SnBytes, Result);
|
|
CopyMemory(@SnBytes[0], @nDataLen, SIZE_INTEGER);
|
|
CopyMemory(@SnBytes[4], @sJsonData[1], nDataLen);
|
|
// SetLength(sJsonData, 0);
|
|
end;
|
|
end;
|
|
|
|
function TTgPacket.ToBytesDataOnly(var SnBytes: TSnBytes): Integer;
|
|
var
|
|
sJsonData: UTF8String;
|
|
begin
|
|
Result := 0;
|
|
sJsonData := UTF8Encode(ToJsonString);
|
|
if sJsonData <> '' then
|
|
begin
|
|
Result := Length(sJsonData);
|
|
SetLength(SnBytes, Result);
|
|
CopyMemory(@SnBytes[0], @sJsonData[1], Result);
|
|
end;
|
|
end;
|
|
|
|
function TTgPacket.SaveToFile(sPath: String): Boolean;
|
|
var
|
|
ss: TStringStream;
|
|
begin
|
|
Result := false;
|
|
try
|
|
Guard(ss, TStringStream.Create(ToJsonString, TEncoding.UTF8));
|
|
ss.SaveToFile(sPath);
|
|
Result := true;
|
|
except
|
|
//
|
|
end;
|
|
end;
|
|
|
|
procedure TTgPacket.PutO(const sPath: String; const Value: ISuperObject);
|
|
begin
|
|
SuperObject_.O[sPath] := Value;
|
|
end;
|
|
|
|
procedure TTgPacket.PutB(const sPath: String; Value: Boolean);
|
|
begin
|
|
SuperObject_.B[sPath] := Value;
|
|
end;
|
|
|
|
procedure TTgPacket.PutI(const sPath: String; Value: SuperInt);
|
|
begin
|
|
SuperObject_.I[sPath] := Value;
|
|
end;
|
|
|
|
procedure TTgPacket.PutC(const sPath: String; Value: Currency);
|
|
begin
|
|
SuperObject_.C[sPath] := Value;
|
|
end;
|
|
|
|
procedure TTgPacket.PutD(const sPath: String; Value: Double);
|
|
begin
|
|
SuperObject_.D[sPath] := Value;
|
|
end;
|
|
|
|
procedure TTgPacket.PutS(const sPath: String; const Value: String);
|
|
begin
|
|
SuperObject_.S[sPath] := Value;
|
|
end;
|
|
|
|
function TTgPacket.GetO(const sPath: String): ISuperObject;
|
|
begin
|
|
Result := SuperObject_.O[sPath];
|
|
end;
|
|
|
|
function TTgPacket.GetB(const sPath: String): Boolean;
|
|
begin
|
|
Result := SuperObject_.B[sPath];
|
|
end;
|
|
|
|
function TTgPacket.GetI(const sPath: String): SuperInt;
|
|
begin
|
|
Result := SuperObject_.I[sPath];
|
|
end;
|
|
|
|
function TTgPacket.GetD(const sPath: String): Double;
|
|
begin
|
|
Result := SuperObject_.D[sPath];
|
|
end;
|
|
|
|
function TTgPacket.GetC(const sPath: String): Currency;
|
|
begin
|
|
Result := SuperObject_.C[sPath];
|
|
end;
|
|
|
|
function TTgPacket.GetS(const sPath: String): String;
|
|
begin
|
|
Result := SuperObject_.S[sPath];
|
|
end;
|
|
|
|
function TTgPacket.GetA(const sPath: String): TSuperArray;
|
|
begin
|
|
Result := SuperObject_.A[sPath];
|
|
end;
|
|
|
|
function TTgPacket.GetCommand: Integer;
|
|
begin
|
|
Result := PacketHeader_.Cmd;
|
|
end;
|
|
|
|
procedure TTgPacket.SetPacketKind(aPacketKind: TTgPacketKind);
|
|
begin
|
|
if PacketHeader_.PacketKind <> aPacketKind then
|
|
PacketHeader_.PacketKind := aPacketKind;
|
|
end;
|
|
|
|
function TTgPacket.GetPacketKind: TTgPacketKind;
|
|
begin
|
|
Result := PacketHeader_.PacketKind;
|
|
end;
|
|
|
|
procedure TTgPacket.SetHandle(llHandle: LONGLONG);
|
|
begin
|
|
if PacketHeader_.Handle <> llHandle then
|
|
PacketHeader_.Handle := llHandle;
|
|
end;
|
|
|
|
function TTgPacket.GetHandle: LONGLONG;
|
|
begin
|
|
Result := PacketHeader_.Handle;
|
|
end;
|
|
|
|
procedure TTgPacket.SetWndMessage(llWndMessage: LONGLONG);
|
|
begin
|
|
if PacketHeader_.WndMessage <> llWndMessage then
|
|
PacketHeader_.WndMessage := llWndMessage;
|
|
end;
|
|
|
|
function TTgPacket.GetWndMessage: LONGLONG;
|
|
begin
|
|
Result := PacketHeader_.WndMessage;
|
|
end;
|
|
|
|
procedure TTgPacket.SetToss(llToss: LONGLONG);
|
|
begin
|
|
if PacketHeader_.Toss <> llToss then
|
|
PacketHeader_.Toss := llToss;
|
|
end;
|
|
|
|
function TTgPacket.GetToss: LONGLONG;
|
|
begin
|
|
Result := PacketHeader_.Toss;
|
|
end;
|
|
|
|
procedure TTgPacket.SetResult(nResult: Integer);
|
|
begin
|
|
if PacketHeader_.Result <> nResult then
|
|
PacketHeader_.Result := nResult;
|
|
end;
|
|
|
|
function TTgPacket.GetResult: Integer;
|
|
begin
|
|
Result := PacketHeader_.Result;
|
|
end;
|
|
|
|
procedure TTgPacket.SetResultMsg(const sResultMsg: String);
|
|
begin
|
|
if PacketHeader_.ResultMsg <> sResultMsg then
|
|
PacketHeader_.ResultMsg := sResultMsg;
|
|
end;
|
|
|
|
function TTgPacket.GetResultMsg: String;
|
|
begin
|
|
Result := PacketHeader_.ResultMsg;
|
|
end;
|
|
|
|
function TTgPacket.GetSocket: TObject;
|
|
begin
|
|
Result := Socket_;
|
|
{$IFDEF DEBUG}
|
|
if Result = nil then
|
|
raise ETgPacket.Create('소켓이 지정 되지있지 않습니다.');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TTgPacket.SetSocket(aSocket: TObject);
|
|
begin
|
|
if Socket_ <> aSocket then
|
|
Socket_ := aSocket;
|
|
end;
|
|
|
|
function TTgPacket.GetRcvPacketSize: DWORD;
|
|
begin
|
|
Result := dwRcvLen_;
|
|
end;
|
|
|
|
end.
|