From 9bef7a450e0a2177c160d962e1553d6fd4bc728f Mon Sep 17 00:00:00 2001 From: Olly Date: Sun, 3 Dec 2023 01:40:38 +0000 Subject: [PATCH] Add InternetSocket --- Source/Simba.lpi | 6 +- Source/forms/simba.main.pas | 1 - Source/script/imports/simba.import_web.pas | 73 ++++++++- Source/simba.internetsocket.pas | 179 +++++++++++++++++++++ 4 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 Source/simba.internetsocket.pas diff --git a/Source/Simba.lpi b/Source/Simba.lpi index 79cf86195..d23df84bb 100644 --- a/Source/Simba.lpi +++ b/Source/Simba.lpi @@ -350,7 +350,7 @@ - + @@ -1110,6 +1110,10 @@ + + + + diff --git a/Source/forms/simba.main.pas b/Source/forms/simba.main.pas index 3a26386ce..d90954815 100644 --- a/Source/forms/simba.main.pas +++ b/Source/forms/simba.main.pas @@ -985,7 +985,6 @@ procedure TSimbaForm.SetupDocking; procedure TSimbaForm.SetupCompleted; begin - WriteLn('Setup completed'); if SimbaSettings.FirstLaunch then MenuItemAssociateScripts.Click(); diff --git a/Source/script/imports/simba.import_web.pas b/Source/script/imports/simba.import_web.pas index 7191f1fb8..b59ce4c7c 100644 --- a/Source/script/imports/simba.import_web.pas +++ b/Source/script/imports/simba.import_web.pas @@ -15,7 +15,7 @@ implementation uses lptypes, ffi, fphttpclient, - simba.nativeinterface, simba.httpclient; + simba.nativeinterface, simba.httpclient, simba.internetsocket; (* Web @@ -406,6 +406,66 @@ procedure _LapeSimbaHTTPClient_OnExtractProgress_Write(const Params: PParamArray PSimbaHTTPClient(Params^[0])^.OnExtractProgress := TSimbaHTTPExtractingEvent(Params^[1]^); end; +(* +TSimbaInternetSocket.Create +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +> function TSimbaInternetSocket.Create(AHost: String; APort: UInt16; UseSSL: Boolean): TSimbaInternetSocket; static; +*) +procedure _LapeSimbaInternetSocket_Create(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PSimbaInternetSocket(Result)^ := TSimbaInternetSocket.Create(PString(Params^[0])^, PUInt16(Params^[1])^, PBoolean(Params^[2])^); +end; + +procedure _LapeSimbaInternetSocket_Connect(const Params: PParamArray); LAPE_WRAPPER_CALLING_CONV +begin + PSimbaInternetSocket(Params^[0])^.Connect(); +end; + +procedure _LapeSimbaInternetSocket_HasData(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PBoolean(Result)^ := PSimbaInternetSocket(Params^[0])^.HasData(); +end; + +procedure _LapeSimbaInternetSocket_ReadString(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PString(Result)^ := PSimbaInternetSocket(Params^[0])^.ReadString(PInteger(Params^[1])^); +end; + +procedure _LapeSimbaInternetSocket_ReadStringUntil(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PString(Result)^ := PSimbaInternetSocket(Params^[0])^.ReadStringUntil(PString(Params^[1])^, PInteger(Params^[2])^); +end; + +procedure _LapeSimbaInternetSocket_WriteString(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PInteger(Result)^ := PSimbaInternetSocket(Params^[0])^.WriteString(PString(Params^[1])^); +end; + +procedure _LapeSimbaInternetSocket_GetIOTimeout(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PInteger(Result)^ := PSimbaInternetSocket(Params^[0])^.IOTimeout; +end; + +procedure _LapeSimbaInternetSocket_SetIOTimeout(const Params: PParamArray); LAPE_WRAPPER_CALLING_CONV +begin + PSimbaInternetSocket(Params^[0])^.IOTimeout := PInteger(Params^[1])^; +end; + +procedure _LapeSimbaInternetSocket_GetConnectTimeout(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PInteger(Result)^ := PSimbaInternetSocket(Params^[0])^.ConnectTimeout; +end; + +procedure _LapeSimbaInternetSocket_SetConnectTimeout(const Params: PParamArray); LAPE_WRAPPER_CALLING_CONV +begin + PSimbaInternetSocket(Params^[0])^.ConnectTimeout := PInteger(Params^[1])^; +end; + +procedure _LapeSimbaInternetSocket_LastError(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + PInteger(Result)^ := PSimbaInternetSocket(Params^[0])^.LastError; +end; + procedure ImportWeb(Compiler: TSimbaScript_Compiler); begin with Compiler do @@ -543,6 +603,17 @@ procedure ImportWeb(Compiler: TSimbaScript_Compiler); TSimbaHTTPClient(Ptr^).FreeOnTerminate := True end; + addClass('TInternetSocket'); + addGlobalFunc('function TInternetSocket.Create(AHost: String; APort: UInt16; UseSSL: Boolean = False): TInternetSocket; static;', @_LapeSimbaInternetSocket_Create); + addGlobalFunc('procedure TInternetSocket.Connect;', @_LapeSimbaInternetSocket_Connect); + addGlobalFunc('function TInternetSocket.HasData: Boolean', @_LapeSimbaInternetSocket_HasData); + addGlobalFunc('function TInternetSocket.ReadString(MaxLen: Integer = 8192): String;', @_LapeSimbaInternetSocket_ReadString); + addGlobalFunc('function TInternetSocket.ReadStringUntil(Seq: String; Timeout: Integer): String;', @_LapeSimbaInternetSocket_ReadStringUntil); + addGlobalFunc('function TInternetSocket.WriteString(Str: String): Integer;', @_LapeSimbaInternetSocket_WriteString); + addGlobalFunc('function TInternetSocket.LastError: Integer;', @_LapeSimbaInternetSocket_LastError); + addClassVar('TInternetSocket', 'ConnectTimeout', 'Integer', @_LapeSimbaInternetSocket_GetConnectTimeout, @_LapeSimbaInternetSocket_SetConnectTimeout); + addClassVar('TInternetSocket', 'ReadWriteTimeout', 'Integer', @_LapeSimbaInternetSocket_GetIOTimeout, @_LapeSimbaInternetSocket_SetIOTimeout); + ImportingSection := ''; end; end; diff --git a/Source/simba.internetsocket.pas b/Source/simba.internetsocket.pas new file mode 100644 index 000000000..81283fd2a --- /dev/null +++ b/Source/simba.internetsocket.pas @@ -0,0 +1,179 @@ +{ + Author: Raymond van Venetiƫ and Merlijn Wajer + Project: Simba (https://github.com/MerlijnWajer/Simba) + License: GNU General Public License (https://www.gnu.org/licenses/gpl-3.0) + + Basic internet socket to connect to and read/write strings. +} +unit simba.internetsocket; + +{$i simba.inc} + +interface + +uses + Classes, SysUtils, ssockets, + simba.mufasatypes, simba.baseclass; + +type + PSimbaInternetSocket = ^TSimbaInternetSocket; + TSimbaInternetSocket = class(TSimbaBaseClass) + protected + FSocket: TInetSocket; + FHost: String; + FPort: UInt16; + FUseSSL: Boolean; + + function GetLastError: Integer; + function GetConnectTimeout: Integer; + function GetIOTimeout: Integer; + + procedure SetConnectTimeout(Value: Integer); + procedure SetIOTimeout(Value: Integer); + public + constructor Create(AHost: String; APort: UInt16; UseSSL: Boolean); reintroduce; + destructor Destroy; override; + + procedure Connect; + + function HasData: Boolean; + + function ReadString(MaxLen: Integer = 8192): String; + function ReadStringUntil(Seq: String; Timeout: Integer): String; + function WriteString(Str: String): Integer; + + property IOTimeout: Integer read GetIOTimeout Write SetIOTimeout; + property ConnectTimeout: Integer read GetConnectTimeout Write SetConnectTimeout; + property LastError: Integer read GetLastError; + end; + +implementation + +uses +{$ifdef unix} + BaseUnix, +{$endif} +{$ifdef windows} + WinSock2, +{$endif} + openssl, opensslsockets, sockets; + +// is protected +type + TInetSocketHelper = class helper for TInetSocket + function SetSocketBlockingMode(ASocket: Integer; ABlockMode: TBlockingMode; AFDSPtr: Pointer): boolean; + end; + +function TInetSocketHelper.SetSocketBlockingMode(ASocket: Integer; ABlockMode: TBlockingMode; AFDSPtr: Pointer): boolean; +begin + Result := inherited SetSocketBlockingMode(ASocket, ABlockMode, AFDSPtr); +end; + +function TSimbaInternetSocket.GetLastError: Integer; +begin + Result := FSocket.LastError; +end; + +function TSimbaInternetSocket.GetConnectTimeout: Integer; +begin + Result := FSocket.ConnectTimeout; +end; + +function TSimbaInternetSocket.GetIOTimeout: Integer; +begin + Result := FSocket.IOTimeout; +end; + +procedure TSimbaInternetSocket.SetConnectTimeout(Value: Integer); +begin + FSocket.ConnectTimeout := Value; +end; + +procedure TSimbaInternetSocket.SetIOTimeout(Value: Integer); +begin + FSocket.IOTimeout := Value; +end; + +constructor TSimbaInternetSocket.Create(AHost: String; APort: UInt16; UseSSL: Boolean); +begin + inherited Create(); + + FHost := AHost; + FPort := APort; + FUseSSL := UseSSL; + + if FUseSSL then + FSocket := TInetSocket.Create(FHost, FPort, TOpenSSLSocketHandler.GetDefaultHandler()) + else + FSocket := TInetSocket.Create(FHost, FPort, TSocketHandler.Create()); +end; + +destructor TSimbaInternetSocket.Destroy; +begin + if (FSocket <> nil) then + FreeAndNil(FSocket); + + inherited Destroy; +end; + +procedure TSimbaInternetSocket.Connect; +begin + if FUseSSL and (not IsSSLLoaded) then + InitSSLInterface(); + + FSocket.Connect(); +end; + +function TSimbaInternetSocket.HasData: Boolean; +var + FDS: TFDSet; + b: Byte; +begin + FSocket.SetSocketBlockingMode(FSocket.Handle, bmNonBlocking, @FDS); + FSocket.ReadFlags := MSG_PEEK; + + try + Result := FSocket.Read(b, 1) > 0; + finally + FSocket.SetSocketBlockingMode(FSocket.Handle, bmBlocking, @FDS); + FSocket.ReadFlags := 0; + end; +end; + +function TSimbaInternetSocket.WriteString(Str: String): Integer; +begin + if (Length(Str) > 0) then + Result := FSocket.Write(Str[1], Length(Str)) + else + Result := 0; +end; + +function TSimbaInternetSocket.ReadString(MaxLen: Integer): String; +begin + SetLength(Result, MaxLen); + SetLength(Result, FSocket.Read(Result[1], MaxLen)); +end; + +function TSimbaInternetSocket.ReadStringUntil(Seq: String; Timeout: Integer): String; +var + Read: String; + T: Integer; +begin + T := FSocket.IOTimeout; + FSocket.IOTimeout := Timeout; + + Result := ''; + while not Result.EndsWith(Seq) do + begin + Read := ReadString(); + if (Length(Read) = 0) then + Break; + + Result += Read; + end; + + FSocket.IOTimeout := T; +end; + +end. +