shutdown fixes, error event handling

This commit is contained in:
André Mussche 2014-06-25 15:30:18 +02:00
parent 491206d8fb
commit b85079a7cb
3 changed files with 65 additions and 21 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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;