fpextdirect.pp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. {
  2. This file is part of the Free Component Library
  3. Ext.Direct support - http part
  4. Copyright (c) 2007 by Michael Van Canneyt [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit fpextdirect;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$mode objfpc}{$H+}
  15. { $define extdebug}
  16. interface
  17. {$IFDEF FPC_DOTTEDUNITS}
  18. uses
  19. System.Classes, System.SysUtils, FpJson.Data, FpWeb.JsonRpc.Base, FpWeb.JsonRpc.DispExtDirect, FpWeb.JsonRpc.Web, FpWeb.Http.Defs, Fcl.UriParser;
  20. {$ELSE FPC_DOTTEDUNITS}
  21. uses
  22. Classes, SysUtils, fpjson, fpjsonrpc, fpdispextdirect, webjsonrpc, httpdefs, uriparser;
  23. {$ENDIF FPC_DOTTEDUNITS}
  24. Const
  25. // Redefinition for backwards compatibility
  26. {$IFDEF FPC_DOTTEDUNITS}
  27. DefaultExtDirectOptions = FpWeb.JsonRpc.DispExtDirect.DefaultExtDirectOptions;
  28. {$ELSE}
  29. DefaultExtDirectOptions = fpdispextdirect.DefaultExtDirectOptions;
  30. {$ENDIF}
  31. Type
  32. // Redefinition for backwards compatibility
  33. { TCustomExtDirectDispatcher }
  34. TCustomExtDirectDispatcher = Class({$IFDEF FPC_DOTTEDUNITS}FpWeb.JsonRpc.DispExtDirect{$ELSE}fpdispextdirect{$ENDIF}.TCustomExtDirectDispatcher)
  35. Procedure InitContainer(H: TCustomJsonRpcHandler; AContext: TJsonRpcCallContext; AContainer: TComponent); override;
  36. end;
  37. { TExtDirectDispatcher }
  38. TExtDirectDispatcher = Class(TCustomExtDirectDispatcher)
  39. Published
  40. Property NameSpace;
  41. Property URL;
  42. Property APIType;
  43. Property OnStartBatch;
  44. Property OnDispatchRequest;
  45. Property OnFindHandler;
  46. Property OnEndBatch;
  47. Property Options;
  48. end;
  49. { TCustomExtDirectContentProducer }
  50. TCustomExtDirectContentProducer = Class(TCustomJsonRpcContentProducer)
  51. Protected
  52. Function GetIDProperty : String; override;
  53. Procedure DoGetContent(ARequest : TRequest; Content : TStream; Var Handled : Boolean); override;
  54. end;
  55. { TExtDirectContentProducer }
  56. TExtDirectContentProducer = Class(TCustomExtDirectContentProducer)
  57. private
  58. FDispatcher: TCustomExtDirectDispatcher;
  59. procedure SetDispatcher(const AValue: TCustomExtDirectDispatcher);
  60. Protected
  61. Function GetDispatcher : TCustomJsonRpcDispatcher; override;
  62. procedure Notification(AComponent: TComponent; Operation: TOperation);override;
  63. Published
  64. Property Dispatcher : TCustomExtDirectDispatcher Read FDispatcher Write SetDispatcher;
  65. end;
  66. { TCustomExtDirectModule }
  67. TCustomExtDirectModule = Class(TJsonRpcDispatchModule)
  68. private
  69. FAPIPath: String;
  70. FDispatcher: TCustomExtDirectDispatcher;
  71. FNameSpace: String;
  72. FOptions: TJsonRpcDispatchOptions;
  73. FRequest: TRequest;
  74. FResponse: TResponse;
  75. FRouterPath: String;
  76. procedure SetDispatcher(const AValue: TCustomExtDirectDispatcher);
  77. Protected
  78. // Create API
  79. procedure CreateAPI(ADispatcher: TCustomExtDirectDispatcher; ARequest: TRequest; AResponse: TResponse); virtual;
  80. Function CreateDispatcher : TCustomExtDirectDispatcher; virtual;
  81. procedure Notification(AComponent: TComponent; Operation: TOperation);override;
  82. // Set to a custom dispatcher. If not set, one is created (and kept for all subsequent requests)
  83. Property Dispatcher : TCustomExtDirectDispatcher Read FDispatcher Write SetDispatcher;
  84. // Options to use when creating a dispatcher.
  85. Property DispatchOptions : TJsonRpcDispatchOptions Read FOptions Write FOptions default DefaultDispatchOptions;
  86. // API path/action. Append to BaseURL to get API. Default 'API'
  87. Property APIPath : String Read FAPIPath Write FAPIPath;
  88. // Router path/action. Append to baseURL to get router. Default 'router'
  89. Property RouterPath : String Read FRouterPath Write FRouterPath;
  90. // Namespace
  91. Property NameSpace : String Read FNameSpace Write FNameSpace;
  92. Public
  93. Constructor CreateNew(AOwner : TComponent; CreateMode : Integer); override;
  94. Procedure HandleRequest(ARequest : TRequest; AResponse : TResponse); override;
  95. // Access to request
  96. Property Request: TRequest Read FRequest;
  97. // Access to response
  98. Property Response: TResponse Read FResponse;
  99. end;
  100. TExtDirectModule = Class(TCustomExtDirectModule)
  101. Published
  102. Property Dispatcher;
  103. Property DispatchOptions;
  104. Property APIPath;
  105. Property RouterPath;
  106. Property CreateSession;
  107. Property NameSpace;
  108. Property BaseURL;
  109. Property AfterInitModule;
  110. Property Kind;
  111. Property Session;
  112. Property OnNewSession;
  113. Property OnSessionExpired;
  114. Property CORS;
  115. end;
  116. implementation
  117. {$IFDEF FPC_DOTTEDUNITS}
  118. uses {$ifdef extdebug}System.Dbugintf,{$endif} FpWeb.JsonRpc.Strings;
  119. {$ELSE FPC_DOTTEDUNITS}
  120. uses {$ifdef extdebug}dbugintf,{$endif} fprpcstrings;
  121. {$ENDIF FPC_DOTTEDUNITS}
  122. { TCustomExtDirectDispatcher }
  123. Procedure TCustomExtDirectDispatcher.InitContainer(H: TCustomJsonRpcHandler;
  124. AContext: TJsonRpcCallContext; AContainer: TComponent);
  125. begin
  126. inherited InitContainer(H, AContext, AContainer);
  127. If (AContext is TJsonRpcSessionContext) and (AContainer is TCustomJsonRpcModule) then
  128. TCustomJsonRpcModule(AContainer).Session:=TJsonRpcSessionContext(AContext).Session;
  129. end;
  130. { TCustomExtDirectContentProducer }
  131. function TCustomExtDirectContentProducer.GetIDProperty: String;
  132. begin
  133. Result:='tid';
  134. end;
  135. procedure TCustomExtDirectContentProducer.DoGetContent(ARequest: TRequest;
  136. Content: TStream; var Handled: Boolean);
  137. Var
  138. A,R: String;
  139. begin
  140. A:=ARequest.GetNextPathInfo;
  141. If (A<>'router') then
  142. begin
  143. R:=TCustomExtDirectDispatcher(GetDispatcher).APIAsString;
  144. Content.WriteBuffer(R[1],Length(R));
  145. Handled:=True;
  146. end
  147. else
  148. inherited DoGetContent(ARequest, Content, Handled);
  149. end;
  150. { TExtDirectContentProducer }
  151. procedure TExtDirectContentProducer.SetDispatcher(
  152. const AValue: TCustomExtDirectDispatcher);
  153. begin
  154. if FDispatcher=AValue then exit;
  155. If Assigned(FDispatcher) then
  156. FDispatcher.RemoveFreeNotification(Self);
  157. FDispatcher:=AValue;
  158. If Assigned(FDispatcher) then
  159. FDispatcher.FreeNotification(Self);
  160. end;
  161. function TExtDirectContentProducer.GetDispatcher: TCustomJsonRpcDispatcher;
  162. begin
  163. Result:=FDispatcher;
  164. end;
  165. procedure TExtDirectContentProducer.Notification(AComponent: TComponent;
  166. Operation: TOperation);
  167. begin
  168. inherited Notification(AComponent, Operation);
  169. If (Operation=opRemove) and (AComponent=FDispatcher) then
  170. FDispatcher:=Nil;
  171. end;
  172. { TCustomExtDirectModule }
  173. procedure TCustomExtDirectModule.SetDispatcher(
  174. const AValue: TCustomExtDirectDispatcher);
  175. begin
  176. if FDispatcher=AValue then exit;
  177. If Assigned(FDispatcher) then
  178. FDispatcher.RemoveFreeNotification(Self);
  179. FDispatcher:=AValue;
  180. If Assigned(FDispatcher) then
  181. FDispatcher.FreeNotification(Self);
  182. end;
  183. function TCustomExtDirectModule.CreateDispatcher: TCustomExtDirectDispatcher;
  184. Var
  185. E : TExtDirectDispatcher;
  186. begin
  187. E:=TExtDirectDispatcher.Create(Self);
  188. E.Options:=DispatchOptions;
  189. E.URL:=IncludeHTTPPathDelimiter(BaseURL)+RouterPath;
  190. E.NameSpace:=NameSpace;
  191. Result:=E
  192. end;
  193. procedure TCustomExtDirectModule.Notification(AComponent: TComponent;
  194. Operation: TOperation);
  195. begin
  196. inherited Notification(AComponent, Operation);
  197. If (Operation=opRemove) and (AComponent=FDispatcher) then
  198. FDispatcher:=Nil;
  199. end;
  200. constructor TCustomExtDirectModule.CreateNew(AOwner: TComponent;
  201. CreateMode: Integer);
  202. begin
  203. inherited CreateNew(AOwner, CreateMode);
  204. FOptions:=DefaultDispatchOptions+[jdoSearchRegistry];
  205. APIPath:='API';
  206. RouterPath:='router'
  207. end;
  208. procedure TCustomExtDirectModule.CreateAPI(ADispatcher : TCustomExtDirectDispatcher; ARequest: TRequest; AResponse: TResponse);
  209. begin
  210. AResponse.Content:=ADispatcher.APIAsString;
  211. AResponse.ContentLength:=Length(AResponse.Content);
  212. end;
  213. procedure TCustomExtDirectModule.HandleRequest(ARequest: TRequest;
  214. AResponse: TResponse);
  215. Var
  216. Disp : TCustomExtDirectDispatcher;
  217. res : TJSONData;
  218. R : String;
  219. begin
  220. Self.FRequest:=aRequest;
  221. Self.FResponse:=aResponse;
  222. try
  223. {$ifdef extdebug}SendDebug('Ext.Direct handlerequest: checking session');{$endif}
  224. CheckSession(ARequest);
  225. {$ifdef extdebug}SendDebug('Ext.Direct handlerequest: init session ');{$endif}
  226. InitSession(AResponse);
  227. {$ifdef extdebug}SendDebug('Ext.Direct creating dispatcher');{$endif}
  228. If (Dispatcher=Nil) then
  229. Dispatcher:=CreateDispatcher;
  230. {$ifdef extdebug}SendDebugFmt('Ext.Direct handlerequest: dispatcher class is "%s"',[Dispatcher.Classname]);{$endif}
  231. Disp:=Dispatcher as TCustomExtDirectDispatcher;
  232. R:=ARequest.QueryFields.Values['action'];
  233. If (R='') then
  234. R:=ARequest.GetNextPathInfo;
  235. {$ifdef extdebug}SendDebugFmt('Ext.Direct handlerequest: action is "%s"',[R]);{$endif}
  236. if not CORS.HandleRequest(aRequest,aResponse,[hcDetect,hcSend]) then
  237. If (CompareText(R,APIPath)=0) then
  238. begin
  239. CreateAPI(Disp,ARequest,AResponse);
  240. UpdateSession(AResponse);
  241. AResponse.SendResponse;
  242. end
  243. else if (CompareText(R,RouterPath)=0) then
  244. begin
  245. Res:=DispatchRequest(ARequest,Disp);
  246. try
  247. UpdateSession(AResponse);
  248. If Assigned(Res) then
  249. AResponse.Content:=Res.AsJSON;
  250. AResponse.SendResponse;
  251. finally
  252. Res.Free;
  253. end;
  254. end
  255. else
  256. JsonRpcError(SErrInvalidPath);
  257. finally
  258. Self.FRequest:=Nil;
  259. Self.FResponse:=Nil;
  260. end;
  261. end;
  262. end.