OSDN Git Service

再接続処理がらみの修正(2)
[winbottle/winbottle.git] / sakurasuite / IdSLPP20.pas
1 {*******************************************************}
2 {       IdSLPP20 - Indy Client for SLPP Connection      }
3 {                                                       }
4 {       Copyright (c) 2002-2003 naruto/CANO-Lab         }
5 {*******************************************************}
6
7 unit IdSLPP20;
8
9 interface
10
11 uses
12   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
13   IdTCPClient, IdGlobal, IdException;
14
15 const
16   SLPP_PORT = 9871;
17   SLPP_HOST = 'bottle.mikage.to';
18
19 type
20   TIdSLPPEventType = (etConnectOk, etScript, etMemberCount, etChannelCount,
21                     etChannelList, etUnicast, etForceBroadcast, etCloseChannel,
22                     etForceBroadcastInformation, etBroadcastInformation);
23   TIdSLPPEvent = procedure (Sender: TObject;
24     EventType: TIdSlppEventType; const Param: String) of Object;
25
26   TIdSLPP20 = class;
27
28   TIdSLPP20ReadThread = class(TThread)
29   private
30   protected
31     FClient: TIdSLPP20;
32     FRecvData: TStringList;
33     FEvent: TIdSLPPEventType; // SLPP Command
34     FParam: String;           // SLPP Command Parameter
35     FReceivedLog: TStringList;
36     function Parse: boolean;
37     procedure Execute; override;
38   public
39     constructor Create(AClient: TIdSLPP20); reintroduce;
40     property  Client: TIdSLPP20 read FClient;
41   end;
42
43   TIdSLPP20 = class(TIdTCPClient)
44   private
45     FSLPPThread: TIdSLPP20ReadThread;
46     FDebugMode: boolean;
47     FProxyMode: boolean;
48     FLUID: String;
49     FOnSlppEvent: TIdSlppEvent;
50     FOnConnect: TNotifyEvent;
51     FOnDisconnect: TNotifyEvent;
52     FLastReadTime: Int64;
53     FTimeout: Integer;
54     FOnConnectFailed: TNotifyEvent;
55     procedure SetDebugMode(const Value: boolean);
56     procedure SetLUID(const Value: String);
57     procedure SetOnSlppEvent(const Value: TIdSlppEvent);
58     procedure SetProxyMode(const Value: boolean);
59     procedure SetOnConnect(const Value: TNotifyEvent);
60     procedure SetOnDisconnect(const Value: TNotifyEvent);
61     function GetLastReadTimeInterval: integer;
62     procedure SetLastReadTime(const Value: Int64);
63     procedure SetOnConnectFailed(const Value: TNotifyEvent);
64   public
65     constructor Create(AOwner: TComponent); override;
66     destructor Destroy; override;
67     procedure Connect(const ATimeout: Integer = IdTimeoutDefault); override;
68     procedure ConnectServer(const ATimeout: Integer = IdTimeoutDefault);
69     procedure Disconnect; override;
70     procedure DoOnSlppEvent;
71     procedure DoOnConnect;
72     procedure DoOnConnectFailed;
73     property SLPP20ReadThread: TIdSLPP20ReadThread read FSLPPThread;
74     property LastReadTime: Int64 read FLastReadTime write SetLastReadTime;
75     property LastReadTimeInterval: integer read GetLastReadTimeInterval;
76   published
77     property LUID: String read FLUID write SetLUID;
78     property Port default SLPP_PORT;
79     property DebugMode: boolean read FDebugMode write SetDebugMode;
80     property ProxyMode: boolean read FProxyMode write SetProxyMode;
81     property OnConnect: TNotifyEvent read FOnConnect write SetOnConnect;
82     property OnConnectFailed: TNotifyEvent read FOnConnectFailed write SetOnConnectFailed;
83     property OnDisconnect: TNotifyEvent read FOnDisconnect write SetOnDisconnect;
84     property OnSLPPEvent: TIdSlppEvent read FOnSlppEvent write SetOnSlppEvent;
85     {ProxyMode = true\82Ì\82Æ\82«\82Í\81AHost, Port\82É\83v\83\8d\83L\83V\96¼\82ð}
86   end;
87
88   EIdSlppError = class(EIdException);
89   EIdSlppClientConnectError = class(EIdSlppError);
90
91 procedure Register;
92
93 implementation
94
95 procedure Register;
96 begin
97   RegisterComponents('Indy Clients', [TIdSLPP20]);
98 end;
99
100 { TIdSLPP20 }
101
102 procedure TIdSLPP20.Connect(const ATimeout: Integer);
103 begin
104   inherited Connect(ATimeout);
105 end;
106
107 procedure TIdSLPP20.ConnectServer;
108 begin
109   try
110     FTimeout := ATimeout;
111     FSLPPThread := TIdSLPP20ReadThread.Create(self);
112   except on E: EIdSocketError do
113     raise EIdSlppClientConnectError.Create('Connection Failed');
114   end;
115 end;
116
117 constructor TIdSLPP20.Create(AOwner: TComponent);
118 begin
119   inherited Create(AOwner);
120   Port := SLPP_PORT;
121   Host := SLPP_HOST;
122 end;
123
124 destructor TIdSLPP20.Destroy;
125 begin
126   inherited;
127 end;
128
129 procedure TIdSLPP20.Disconnect;
130 begin
131   inherited Disconnect;
132   if Assigned(FSLPPThread) then begin
133     FSLPPThread.Terminate;
134     // FSLPPThread.WaitFor;
135     FSLPPThread := nil;
136   end;
137   if Assigned(FOnDisconnect) then begin
138     OnDisconnect(self);
139   end;
140 end;
141
142 procedure TIdSLPP20.DoOnConnect;
143 begin
144   if Assigned(FOnConnect) then
145     FOnConnect(self);
146 end;
147
148 procedure TIdSLPP20.DoOnConnectFailed;
149 begin
150   if Assigned(FOnConnectFailed) then
151     FOnConnectFailed(self);
152 end;
153
154 procedure TIdSLPP20.DoOnSlppEvent;
155 begin
156   try
157     FOnSlppEvent(self, FSLPPThread.FEvent, FSLPPThread.FParam);
158   except
159     on E: Exception do
160       ShowMessage('Exception occured in OnSlppEvent: '#13#10 + E.Message);
161   end;
162 end;
163
164 function TIdSLPP20.GetLastReadTimeInterval: integer;
165 begin
166   Result := 0;
167   if Connected then Result := GetTickCount - FLastReadTime;
168 end;
169
170 procedure TIdSLPP20.SetDebugMode(const Value: boolean);
171 begin
172   FDebugMode := Value;
173 end;
174
175 procedure TIdSLPP20.SetLastReadTime(const Value: Int64);
176 begin
177   FLastReadTime := Value;
178 end;
179
180 procedure TIdSLPP20.SetLUID(const Value: String);
181 begin
182   FLUID := Value;
183 end;
184
185 procedure TIdSLPP20.SetOnConnect(const Value: TNotifyEvent);
186 begin
187   FOnConnect := Value;
188 end;
189
190 procedure TIdSLPP20.SetOnConnectFailed(const Value: TNotifyEvent);
191 begin
192   FOnConnectFailed := Value;
193 end;
194
195 procedure TIdSLPP20.SetOnDisconnect(const Value: TNotifyEvent);
196 begin
197   FOnDisconnect := Value;
198 end;
199
200 procedure TIdSLPP20.SetOnSlppEvent(const Value: TIdSlppEvent);
201 begin
202   FOnSlppEvent := Value;
203 end;
204
205 procedure TIdSLPP20.SetProxyMode(const Value: boolean);
206 begin
207   FProxyMode := Value;
208 end;
209
210 { TIdSLPP20ReadThread }
211
212 constructor TIdSLPP20ReadThread.Create(AClient: TIdSLPP20);
213 begin
214   inherited Create(true);
215   FClient := AClient;
216   FreeOnTerminate := true;
217   Resume;
218 end;
219
220 procedure TIdSLPP20ReadThread.Execute;
221 var Line: String;
222 begin
223   try
224     FClient.Connect(FClient.FTimeout);
225     if Assigned(FClient.OnConnect) then begin
226       Synchronize(FClient.DoOnConnect);
227     end;
228   except
229     Synchronize(FClient.DoOnConnectFailed);
230     Exit;
231   end;
232
233   FRecvData := TStringList.Create;
234   FReceivedLog := TStringList.Create;
235   if FClient.ProxyMode then begin
236     FClient.Writeln('POST http://bottle.mikage.to:9871/ HTTP/1.0');
237     FClient.Writeln('Content-Length: ' + IntToStr(Length(FClient.LUID)));
238     FClient.Writeln('Connection: close');
239     FClient.Writeln;
240     FClient.Writeln(FClient.LUID);
241   end else begin
242     FClient.WriteLn('POST / HTTP/1.0');
243     FClient.WriteLn;
244     FClient.WriteLn(FClient.LUID);
245   end;
246   while not Terminated do begin
247     try
248       FClient.CheckForDisconnect;
249       Line := FClient.ReadLn(EOL);
250       if FClient.DebugMode then begin
251         FReceivedLog.Add(Line);
252         FReceivedLog.SaveToFile(ExtractFilePath(Application.ExeName)+'slpp20_debug.log');
253       end;
254       if not FClient.ReadLnTimedOut then FClient.LastReadTime := getTickCount; 
255       if Length(Line) = 0 then begin
256         if FRecvData.Count > 0 then begin
257           FClient.CheckForDisconnect; //\90Ø\92f\8cã\82Ì\92\86\93r\94¼\92[\82È\83f\81[\83^\91\97\90M\82ð\96h\82®
258           while Parse do begin
259             Synchronize(FClient.DoOnSlppEvent);
260           end;
261           FRecvData.Clear;
262         end;
263       end else begin
264         FRecvData.Add(Line);
265       end;
266     except
267       on EIdException do begin
268         Synchronize(self.Terminate);
269       end;
270     end;
271   end;
272
273   if ( FClient.Connected ) then FClient.Disconnect;
274   FreeAndNil(FReceivedLog);
275   FreeAndNil(FRecvData);
276 end;
277
278 function TIdSLPP20ReadThread.Parse: boolean;
279 var
280   command: String;
281 begin
282   command := FRecvData[0];
283   FRecvData.Delete(0);
284   FParam := FRecvData.Text;
285
286   Result := true;
287   if command = 'broadcastMessage' then begin
288     FEvent := etScript;
289   end else if command = 'allUsers' then begin
290     FEvent := etMemberCount;
291   end else if command = 'channelUsers' then begin
292     FEvent := etChannelCount;
293   end else if command = 'channelList' then begin
294     FEvent := etChannelList;
295   end else if (command = 'HTTP/1.0 200 OK') or (command = 'HTTP/1.1 200 OK') then begin
296     FEvent := etConnectOk;
297   end else if command = 'forceBroadcastMessage' then begin
298     FEvent := etForceBroadcast;
299   end else if command = 'forceBroadcastInformation' then begin
300     FEvent := etForceBroadcastInformation;
301   end else if command = 'BroadcastInformation' then begin
302     FEvent := etBroadcastInformation;
303   end else if command = 'closeChannel' then begin
304     FEvent := etCloseChannel;
305   end else if command = 'unicastMessage' then begin
306     FEvent := etUnicast;
307   end else Result := false;
308 end;
309
310 end.