shutdown fixes, error event handling
This commit is contained in:
parent
491206d8fb
commit
b85079a7cb
3 changed files with 65 additions and 21 deletions
|
@ -184,6 +184,9 @@ uses
|
||||||
IdCoderMIME, SysUtils, Math, IdException, IdStackConsts, IdStack,
|
IdCoderMIME, SysUtils, Math, IdException, IdStackConsts, IdStack,
|
||||||
IdStackBSDBase, IdGlobal, Windows, StrUtils, DateUtils;
|
IdStackBSDBase, IdGlobal, Windows, StrUtils, DateUtils;
|
||||||
|
|
||||||
|
var
|
||||||
|
GUnitFinalized: Boolean = false;
|
||||||
|
|
||||||
//type
|
//type
|
||||||
// TAnonymousThread = class(TThread)
|
// TAnonymousThread = class(TThread)
|
||||||
// protected
|
// protected
|
||||||
|
@ -1148,6 +1151,8 @@ procedure TIdWebsocketMultiReadThread.AddClient(
|
||||||
var l: TList;
|
var l: TList;
|
||||||
begin
|
begin
|
||||||
//Assert( (aChannel.IOHandler as TIdIOHandlerWebsocket).IsWebsocket, 'Channel is not a websocket');
|
//Assert( (aChannel.IOHandler as TIdIOHandlerWebsocket).IsWebsocket, 'Channel is not a websocket');
|
||||||
|
if Self = nil then Exit;
|
||||||
|
if Self.Terminated then Exit;
|
||||||
|
|
||||||
l := FChannels.LockList;
|
l := FChannels.LockList;
|
||||||
try
|
try
|
||||||
|
@ -1212,6 +1217,13 @@ end;
|
||||||
|
|
||||||
destructor TIdWebsocketMultiReadThread.Destroy;
|
destructor TIdWebsocketMultiReadThread.Destroy;
|
||||||
begin
|
begin
|
||||||
|
if FReconnectThread <> nil then
|
||||||
|
begin
|
||||||
|
FReconnectThread.Terminate;
|
||||||
|
FReconnectThread.WaitFor;
|
||||||
|
FReconnectThread.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
IdWinsock2.closesocket(FTempHandle);
|
IdWinsock2.closesocket(FTempHandle);
|
||||||
FTempHandle := 0;
|
FTempHandle := 0;
|
||||||
FChannels.Free;
|
FChannels.Free;
|
||||||
|
@ -1256,6 +1268,8 @@ class function TIdWebsocketMultiReadThread.Instance: TIdWebsocketMultiReadThread
|
||||||
begin
|
begin
|
||||||
if (FInstance = nil) then
|
if (FInstance = nil) then
|
||||||
begin
|
begin
|
||||||
|
if GUnitFinalized then Exit(nil);
|
||||||
|
|
||||||
FInstance := TIdWebsocketMultiReadThread.Create(True);
|
FInstance := TIdWebsocketMultiReadThread.Create(True);
|
||||||
FInstance.Start;
|
FInstance.Start;
|
||||||
end;
|
end;
|
||||||
|
@ -1269,6 +1283,8 @@ var
|
||||||
ws: TIdIOHandlerWebsocket;
|
ws: TIdIOHandlerWebsocket;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
|
if Terminated then Exit;
|
||||||
|
|
||||||
l := FChannels.LockList;
|
l := FChannels.LockList;
|
||||||
try
|
try
|
||||||
for i := 0 to l.Count - 1 do
|
for i := 0 to l.Count - 1 do
|
||||||
|
@ -1311,8 +1327,11 @@ begin
|
||||||
FChannels.UnlockList;
|
FChannels.UnlockList;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if Terminated then Exit;
|
||||||
|
|
||||||
//reconnect needed? (in background)
|
//reconnect needed? (in background)
|
||||||
if (FReconnectlist <> nil) and (FReconnectlist.Count > 0) then
|
if FReconnectlist <> nil then
|
||||||
|
if FReconnectlist.Count > 0 then
|
||||||
begin
|
begin
|
||||||
if FReconnectThread = nil then
|
if FReconnectThread = nil then
|
||||||
FReconnectThread := TIdWebsocketQueueThread.Create(False{direct start});
|
FReconnectThread := TIdWebsocketQueueThread.Create(False{direct start});
|
||||||
|
@ -1456,7 +1475,8 @@ begin
|
||||||
//some data?
|
//some data?
|
||||||
if (iResult > 0) then
|
if (iResult > 0) then
|
||||||
begin
|
begin
|
||||||
//strmEvent := nil;
|
//make sure the thread is created outside a lock
|
||||||
|
TIdWebsocketDispatchThread.Instance;
|
||||||
|
|
||||||
l := FChannels.LockList;
|
l := FChannels.LockList;
|
||||||
if l = nil then Exit;
|
if l = nil then Exit;
|
||||||
|
@ -1503,6 +1523,7 @@ procedure TIdWebsocketMultiReadThread.RemoveClient(
|
||||||
aChannel: TIdHTTPWebsocketClient);
|
aChannel: TIdHTTPWebsocketClient);
|
||||||
begin
|
begin
|
||||||
if Self = nil then Exit;
|
if Self = nil then Exit;
|
||||||
|
if Self.Terminated then Exit;
|
||||||
|
|
||||||
aChannel.Lock;
|
aChannel.Lock;
|
||||||
try
|
try
|
||||||
|
@ -1516,18 +1537,23 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class procedure TIdWebsocketMultiReadThread.RemoveInstance(aForced: boolean);
|
class procedure TIdWebsocketMultiReadThread.RemoveInstance(aForced: boolean);
|
||||||
|
var
|
||||||
|
o: TIdWebsocketMultiReadThread;
|
||||||
begin
|
begin
|
||||||
if FInstance <> nil then
|
if FInstance <> nil then
|
||||||
begin
|
begin
|
||||||
FInstance.Terminate;
|
FInstance.Terminate;
|
||||||
|
o := FInstance;
|
||||||
|
FInstance := nil;
|
||||||
|
|
||||||
if aForced then
|
if aForced then
|
||||||
begin
|
begin
|
||||||
WaitForSingleObject(FInstance.Handle, 2 * 1000);
|
WaitForSingleObject(o.Handle, 2 * 1000);
|
||||||
TerminateThread(FInstance.Handle, MaxInt);
|
TerminateThread(o.Handle, MaxInt);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
FInstance.WaitFor;
|
o.WaitFor;
|
||||||
FreeAndNil(FInstance);
|
FreeAndNil(o);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -1544,6 +1570,8 @@ end;
|
||||||
procedure TIdWebsocketMultiReadThread.Terminate;
|
procedure TIdWebsocketMultiReadThread.Terminate;
|
||||||
begin
|
begin
|
||||||
inherited Terminate;
|
inherited Terminate;
|
||||||
|
if FReconnectThread <> nil then
|
||||||
|
FReconnectThread.Terminate;
|
||||||
|
|
||||||
FChannels.LockList;
|
FChannels.LockList;
|
||||||
try
|
try
|
||||||
|
@ -1560,6 +1588,8 @@ class function TIdWebsocketDispatchThread.Instance: TIdWebsocketDispatchThread;
|
||||||
begin
|
begin
|
||||||
if FInstance = nil then
|
if FInstance = nil then
|
||||||
begin
|
begin
|
||||||
|
if GUnitFinalized then Exit(nil);
|
||||||
|
|
||||||
GlobalNameSpace.BeginWrite;
|
GlobalNameSpace.BeginWrite;
|
||||||
try
|
try
|
||||||
if FInstance = nil then
|
if FInstance = nil then
|
||||||
|
@ -1575,17 +1605,22 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class procedure TIdWebsocketDispatchThread.RemoveInstance;
|
class procedure TIdWebsocketDispatchThread.RemoveInstance;
|
||||||
|
var
|
||||||
|
o: TIdWebsocketDispatchThread;
|
||||||
begin
|
begin
|
||||||
if FInstance <> nil then
|
if FInstance <> nil then
|
||||||
begin
|
begin
|
||||||
FInstance.Terminate;
|
FInstance.Terminate;
|
||||||
|
o := FInstance;
|
||||||
|
FInstance := nil;
|
||||||
|
|
||||||
if aForced then
|
if aForced then
|
||||||
begin
|
begin
|
||||||
WaitForSingleObject(FInstance.Handle, 2 * 1000);
|
WaitForSingleObject(o.Handle, 2 * 1000);
|
||||||
TerminateThread(FInstance.Handle, MaxInt);
|
TerminateThread(o.Handle, MaxInt);
|
||||||
end;
|
end;
|
||||||
FInstance.WaitFor;
|
o.WaitFor;
|
||||||
FreeAndNil(FInstance);
|
FreeAndNil(o);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -1604,7 +1639,9 @@ end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
finalization
|
finalization
|
||||||
|
GUnitFinalized := True;
|
||||||
|
if TIdWebsocketMultiReadThread.Instance <> nil then
|
||||||
|
TIdWebsocketMultiReadThread.Instance.Terminate;
|
||||||
|
TIdWebsocketDispatchThread.RemoveInstance();
|
||||||
TIdWebsocketMultiReadThread.RemoveInstance();
|
TIdWebsocketMultiReadThread.RemoveInstance();
|
||||||
TIdWebsocketDispatchThread.RemoveInstance()
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -6,7 +6,7 @@ uses
|
||||||
Classes, Generics.Collections,
|
Classes, Generics.Collections,
|
||||||
superobject,
|
superobject,
|
||||||
IdServerBaseHandling, IdContext, IdException, IdIOHandlerWebsocket, IdHTTP,
|
IdServerBaseHandling, IdContext, IdException, IdIOHandlerWebsocket, IdHTTP,
|
||||||
SyncObjs;
|
SyncObjs, SysUtils;
|
||||||
|
|
||||||
type
|
type
|
||||||
TSocketIOContext = class;
|
TSocketIOContext = class;
|
||||||
|
@ -22,6 +22,7 @@ type
|
||||||
TSocketIONotify = reference to procedure(const ASocket: ISocketIOContext);
|
TSocketIONotify = reference to procedure(const ASocket: ISocketIOContext);
|
||||||
TSocketIOEvent = reference to procedure(const ASocket: ISocketIOContext; const aArgument: TSuperArray; const aCallback: ISocketIOCallback);
|
TSocketIOEvent = reference to procedure(const ASocket: ISocketIOContext; const aArgument: TSuperArray; const aCallback: ISocketIOCallback);
|
||||||
TSocketIOError = reference to procedure(const ASocket: ISocketIOContext; const aErrorClass, aErrorMessage: string);
|
TSocketIOError = reference to procedure(const ASocket: ISocketIOContext; const aErrorClass, aErrorMessage: string);
|
||||||
|
TSocketIOEventError = reference to procedure(const ASocket: ISocketIOContext; const aCallback: ISocketIOCallback; E: Exception);
|
||||||
|
|
||||||
TSocketIONotifyList = class(TList<TSocketIONotify>);
|
TSocketIONotifyList = class(TList<TSocketIONotify>);
|
||||||
TSocketIOEventList = class(TList<TSocketIOEvent>);
|
TSocketIOEventList = class(TList<TSocketIOEvent>);
|
||||||
|
@ -139,6 +140,8 @@ type
|
||||||
FOnSocketIOJson: TSocketIOMsgJSON;
|
FOnSocketIOJson: TSocketIOMsgJSON;
|
||||||
|
|
||||||
procedure ProcessEvent(const AContext: TSocketIOContext; const aText: string; aMsgNr: Integer; aHasCallback: Boolean);
|
procedure ProcessEvent(const AContext: TSocketIOContext; const aText: string; aMsgNr: Integer; aHasCallback: Boolean);
|
||||||
|
private
|
||||||
|
FOnEventError: TSocketIOEventError;
|
||||||
protected
|
protected
|
||||||
type
|
type
|
||||||
TSocketIOCallback = procedure(const aData: string) of object;
|
TSocketIOCallback = procedure(const aData: string) of object;
|
||||||
|
@ -194,6 +197,7 @@ type
|
||||||
procedure OnEvent (const aEventName: string; const aCallback: TSocketIOEvent);
|
procedure OnEvent (const aEventName: string; const aCallback: TSocketIOEvent);
|
||||||
procedure OnConnection(const aCallback: TSocketIONotify);
|
procedure OnConnection(const aCallback: TSocketIONotify);
|
||||||
procedure OnDisconnect(const aCallback: TSocketIONotify);
|
procedure OnDisconnect(const aCallback: TSocketIONotify);
|
||||||
|
property OnEventError: TSocketIOEventError read FOnEventError write FOnEventError;
|
||||||
|
|
||||||
procedure EnumerateSockets(const aEachSocketCallback: TSocketIONotify);
|
procedure EnumerateSockets(const aEachSocketCallback: TSocketIONotify);
|
||||||
end;
|
end;
|
||||||
|
@ -208,7 +212,7 @@ type
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
SysUtils, StrUtils, IdServerWebsocketContext, IdHTTPWebsocketClient, Windows;
|
StrUtils, IdServerWebsocketContext, IdHTTPWebsocketClient, Windows;
|
||||||
|
|
||||||
procedure TIdBaseSocketIOHandling.AfterConstruction;
|
procedure TIdBaseSocketIOHandling.AfterConstruction;
|
||||||
begin
|
begin
|
||||||
|
@ -501,15 +505,15 @@ begin
|
||||||
else
|
else
|
||||||
callback := nil;
|
callback := nil;
|
||||||
try
|
try
|
||||||
|
for event in list do
|
||||||
try
|
try
|
||||||
for event in list do
|
event(AContext, args, callback);
|
||||||
event(AContext, args, callback);
|
except on E:Exception do
|
||||||
except
|
if Assigned(OnEventError) then
|
||||||
on E:Exception do
|
OnEventError(AContext, callback, e)
|
||||||
begin
|
else
|
||||||
if callback <> nil then
|
if callback <> nil then
|
||||||
callback.SendResponse( SO(['Error', e.Message]).AsJSon );
|
callback.SendResponse( SO(['Error', SO(['msg', e.message])]).AsJSon );
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
callback := nil;
|
callback := nil;
|
||||||
|
|
|
@ -116,18 +116,21 @@ procedure TROIndyHTTPWebsocketChannel.SetHost(const Value: string);
|
||||||
begin
|
begin
|
||||||
IndyClient.Host := Value;
|
IndyClient.Host := Value;
|
||||||
TargetURL := Format('ws://%s:%d/%s', [Host, Port, WSResourceName]);
|
TargetURL := Format('ws://%s:%d/%s', [Host, Port, WSResourceName]);
|
||||||
|
FTriedUpgrade := False; //reset
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TROIndyHTTPWebsocketChannel.SetPort(const Value: integer);
|
procedure TROIndyHTTPWebsocketChannel.SetPort(const Value: integer);
|
||||||
begin
|
begin
|
||||||
IndyClient.Port := Value;
|
IndyClient.Port := Value;
|
||||||
TargetURL := Format('ws://%s:%d/%s', [Host, Port, WSResourceName]);
|
TargetURL := Format('ws://%s:%d/%s', [Host, Port, WSResourceName]);
|
||||||
|
FTriedUpgrade := False; //reset
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TROIndyHTTPWebsocketChannel.SetWSResourceName(const Value: string);
|
procedure TROIndyHTTPWebsocketChannel.SetWSResourceName(const Value: string);
|
||||||
begin
|
begin
|
||||||
IndyClient.WSResourceName := Value;
|
IndyClient.WSResourceName := Value;
|
||||||
TargetURL := Format('ws://%s:%d/%s', [Host, Port, WSResourceName]);
|
TargetURL := Format('ws://%s:%d/%s', [Host, Port, WSResourceName]);
|
||||||
|
FTriedUpgrade := False; //reset
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TROIndyHTTPWebsocketChannel.GetHost: string;
|
function TROIndyHTTPWebsocketChannel.GetHost: string;
|
||||||
|
|
Loading…
Reference in a new issue