├── .gitignore
├── FastReportPrinter.groupproj
├── LICENSE
├── README.md
├── Samples
├── CGI
│ ├── CGI.dpr
│ ├── CGI.dproj
│ ├── CGI.res
│ └── Readme.txt
├── Console
│ ├── Console.dpr
│ ├── Console.dproj
│ └── Console.res
├── ConsoleHorse
│ ├── ConsoleHorse.dpr
│ ├── ConsoleHorse.dproj
│ ├── ConsoleHorse.res
│ └── Readme.txt
├── DB
│ └── FAST_REPORT_PRINTER.FDB
├── FMX
│ ├── FMX.dpr
│ ├── FMX.dproj
│ ├── FMX.res
│ ├── Main.fmx
│ └── Main.pas
├── Horse
│ ├── Horse
│ │ └── src
│ │ │ ├── Horse.Callback.pas
│ │ │ ├── Horse.Commons.pas
│ │ │ ├── Horse.Constants.pas
│ │ │ ├── Horse.Core.Files.pas
│ │ │ ├── Horse.Core.Group.Contract.pas
│ │ │ ├── Horse.Core.Group.pas
│ │ │ ├── Horse.Core.Param.Config.pas
│ │ │ ├── Horse.Core.Param.Field.Brackets.pas
│ │ │ ├── Horse.Core.Param.Field.pas
│ │ │ ├── Horse.Core.Param.Header.pas
│ │ │ ├── Horse.Core.Param.pas
│ │ │ ├── Horse.Core.Route.Contract.pas
│ │ │ ├── Horse.Core.Route.pas
│ │ │ ├── Horse.Core.RouterTree.NextCaller.pas
│ │ │ ├── Horse.Core.RouterTree.pas
│ │ │ ├── Horse.Core.pas
│ │ │ ├── Horse.Exception.Interrupted.pas
│ │ │ ├── Horse.Exception.pas
│ │ │ ├── Horse.Proc.pas
│ │ │ ├── Horse.Provider.Abstract.pas
│ │ │ ├── Horse.Provider.Apache.pas
│ │ │ ├── Horse.Provider.CGI.pas
│ │ │ ├── Horse.Provider.Console.pas
│ │ │ ├── Horse.Provider.Daemon.pas
│ │ │ ├── Horse.Provider.FPC.Apache.pas
│ │ │ ├── Horse.Provider.FPC.CGI.pas
│ │ │ ├── Horse.Provider.FPC.Daemon.pas
│ │ │ ├── Horse.Provider.FPC.FastCGI.pas
│ │ │ ├── Horse.Provider.FPC.HTTPApplication.pas
│ │ │ ├── Horse.Provider.FPC.LCL.pas
│ │ │ ├── Horse.Provider.IOHandleSSL.pas
│ │ │ ├── Horse.Provider.ISAPI.pas
│ │ │ ├── Horse.Provider.VCL.pas
│ │ │ ├── Horse.Request.pas
│ │ │ ├── Horse.Response.pas
│ │ │ ├── Horse.Rtti.Helper.pas
│ │ │ ├── Horse.Rtti.pas
│ │ │ ├── Horse.Session.pas
│ │ │ ├── Horse.WebModule.dfm
│ │ │ ├── Horse.WebModule.lfm
│ │ │ ├── Horse.WebModule.pas
│ │ │ ├── Horse.pas
│ │ │ ├── ThirdParty.Posix.Syslog.pas
│ │ │ └── Web.WebConst.pas
│ └── Staticfiles
│ │ └── src
│ │ └── Horse.StaticFiles.pas
├── ISAPI
│ ├── ISAPI.dpr
│ ├── ISAPI.dproj
│ ├── ISAPI.res
│ └── Readme.txt
├── JMeter
│ └── FastReportPrinter.jmx
├── Postman
│ └── FastReportPrinter.postman_collection_v2.1.json
├── Report
│ └── rptLocalidadesIBGE.fr3
├── Utils
│ ├── Data.pas
│ └── Utils.pas
├── VCL
│ ├── Main.dfm
│ ├── Main.pas
│ ├── Samples.res
│ ├── VCL.dpr
│ ├── VCL.dproj
│ └── VCL.res
├── VCLHorse
│ ├── Main.dfm
│ ├── Main.pas
│ ├── Readme.txt
│ ├── VCLHorse.dpr
│ ├── VCLHorse.dproj
│ └── VCLHorse.res
├── WindowsService
│ ├── Main.dfm
│ ├── Main.pas
│ ├── WindowsServer.res
│ ├── WindowsService.dpr
│ ├── WindowsService.dproj
│ └── WindowsService.res
└── WindowsServiceHorse
│ ├── Main.dfm
│ ├── Main.pas
│ ├── Readme.txt
│ ├── WindowsServiceHorse.dpr
│ ├── WindowsServiceHorse.dproj
│ └── WindowsServiceHorse.res
├── Source
├── FRPrinter.Core.pas
├── FRPrinter.Interfaces.pas
├── FRPrinter.Types.pas
└── FRPrinter.pas
├── boss-lock.json
└── boss.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment these types if you want even more clean repository. But be careful.
2 | # It can make harm to an existing project source. Read explanations below.
3 | #
4 | # Resource files are binaries containing manifest, project icon and version info.
5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
6 | #*.res
7 | #
8 | # Type library file (binary). In old Delphi versions it should be stored.
9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
10 | #*.tlb
11 | #
12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
13 | # Uncomment this if you are not using diagrams or use newer Delphi version.
14 | #*.ddp
15 | #
16 | # Visual LiveBindings file. Added in Delphi XE2.
17 | # Uncomment this if you are not using LiveBindings Designer.
18 | #*.vlb
19 | #
20 | # Deployment Manager configuration file for your project. Added in Delphi XE2.
21 | # Uncomment this if it is not mobile development and you do not use remote debug feature.
22 | #*.deployproj
23 | #
24 | # C++ object files produced when C/C++ Output file generation is configured.
25 | # Uncomment this if you are not using external objects (zlib library for example).
26 | #*.obj
27 | #
28 |
29 | # Delphi compiler-generated binaries (safe to delete)
30 | *.exe
31 | *.dll
32 | *.bpl
33 | *.bpi
34 | *.dcp
35 | *.so
36 | *.apk
37 | *.drc
38 | *.map
39 | *.dres
40 | *.rsm
41 | *.tds
42 | *.dcu
43 | *.lib
44 | *.a
45 | *.o
46 | *.ocx
47 |
48 | # Delphi autogenerated files (duplicated info)
49 | *.cfg
50 | *.hpp
51 | *Resource.rc
52 |
53 | # Delphi local files (user-specific info)
54 | *.local
55 | *.identcache
56 | *.projdata
57 | *.tvsconfig
58 | *.dsk
59 |
60 | # Delphi history and backups
61 | __history/
62 | __recovery/
63 | *.~*
64 |
65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi)
66 | *.stat
67 |
68 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss
69 | modules/
70 |
--------------------------------------------------------------------------------
/FastReportPrinter.groupproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {6755DBF6-C824-4AB4-98C6-B52F48E13E16}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | Default.Personality.12
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 
6 | 
7 | 
8 | 
9 | 
10 |
11 | # FastReportPrinter
12 |
13 | **FastReportPrinter** é uma biblioteca de impressão de relatórios com [Fast Report](https://www.fast-report.com) para ambientes **multithreading** e não **GUI(Graphical User Interface)**.
14 |
15 | Implementado na linguagem Delphi, utiliza o conceito de [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) para guiar no uso da biblioteca, desenvolvido para impressão de relatórios em ambientes não GUI(Graphical User Interface) usando spooler de impressão.
16 |
17 | **Ambientes**
18 |
19 | * Windows Forms
20 | * Windows Console
21 | * Windows Service *
22 | * IIS ISAPI[(Horse)](https://github.com/HashLoad/horse) *
23 | * IIS CGI[(Horse)](https://github.com/HashLoad/horse) *
24 |
25 | ## ⭕ Pré-requisito
26 |
27 | Para utilizar o **FastReportPrinter** é necessário a instalação do componente [Fast Report](https://www.fast-report.com).
28 |
29 | ## ⚙️ Instalação Automatizada
30 |
31 | Utilizando o [**Boss**](https://github.com/HashLoad/boss/releases/latest) (Dependency manager for Delphi) é possível instalar a biblioteca de forma automática.
32 |
33 | ```
34 | boss install github.com/antoniojmsjr/FastReportPrinter
35 | ```
36 |
37 | ## ⚙️ Instalação Manual
38 |
39 | Se você optar por instalar manualmente, basta adicionar as seguintes pastas ao seu projeto, em *Project > Options > Delphi Compiler > Target > All Configurations > Search path*
40 |
41 | ```
42 | ..\FastReportPrinter\Source
43 | ```
44 |
45 | ## 🧬 DataSet de Exportação
46 |
47 | **DataSets** é uma interface utilizada pela biblioteca para comunicação com o banco de dados através dos componentes:
48 |
49 | | Classe | Componente |
50 | |---|---|
51 | | TDataSet | Nativo |
52 | | TfrxDBDataset | Fast Report |
53 |
54 | ## ⚡️ Uso da biblioteca
55 |
56 | Para exemplificar o uso do biblioteca foi utilizado os dados da **[API de localidades do IBGE](https://servicodados.ibge.gov.br/api/docs/localidades)** para geração e impressão do relatório.
57 |
58 | Arquivo de exemplo de impressão: [LocalidadesIBGE.pdf](https://github.com/antoniojmsjr/FastReportPrinter/files/9245473/LocalidadesIBGE.pdf)
59 |
60 | Os exemplos estão disponíveis na pasta do projeto:
61 |
62 | ```
63 | ..\FastReportPrinter\Samples
64 | ```
65 |
66 | **Banco de dados de exemplo**
67 |
68 | * Firebird: 2.5.7 [Donwload](http://sourceforge.net/projects/firebird/files/firebird-win32/2.5.7-Release/Firebird-2.5.7.27050_0_Win32.exe/download)
69 | * Arquivo BD:
70 | ```
71 | ..\FastReportPrinter\Samples\DB
72 | ```
73 |
74 | **Relatório de exemplo**
75 |
76 | ```
77 | ..\FastReportPrinter\Samples\Report
78 | ```
79 | **Exemplo**
80 |
81 | ```delphi
82 | uses FRPrinter, FRPrinter.Types;
83 | ```
84 | ```delphi
85 | var
86 | lPrinted: Boolean;
87 | begin
88 |
89 | //CLASSE DE IMPRESSÃO
90 | try
91 | lPrinted := TFRPrinter.New.
92 | DataSets.
93 | SetDataSet(qryEstadosBrasil, 'EstadosBrasil').
94 | SetDataSet(frxdbMunicipioEstado).
95 | SetDataSet(frxdbMunicipioRegiao).
96 | SetDataSet(qryEstadoRegiao, 'EstadoRegiao').
97 | SetDataSet(qryMunicipios, 'Municipios').
98 | &End.
99 | Print.
100 | SetPrinter('Microsoft Print to PDF'). //QUANDO NÃO INFORMADO UTILIZA A IMPRESSORA CONFIGURADA NO RELATÓRIO *.fr3
101 | SetFileReport(TUtils.PathAppFileReport). //LOCAL DO RELATÓRIO *.fr3
102 | Report(procedure(pfrxReport: TfrxReport) //CONFIGURAÇÃO DO COMPONENTE DE RELATÓRIO DO FAST REPORT
103 | var
104 | lfrxComponent: TfrxComponent;
105 | lfrxMemoView: TfrxMemoView absolute lfrxComponent;
106 | begin
107 | //CONFIGURAÇÃO DO COMPONENTE
108 |
109 | pfrxReport.ReportOptions.Name := 'API de localidades IBGE'; //NOME PARA IDENTIFICAÇÃO NA IMPRESSÃO DO RELATÓRIO
110 | pfrxReport.ReportOptions.Author := 'Antônio José Medeiros Schneider';
111 |
112 | //PASSAGEM DE PARÂMETRO PARA O RELATÓRIO
113 | lfrxComponent := pfrxReport.FindObject('mmoProcess');
114 | if Assigned(lfrxComponent) then
115 | begin
116 | lfrxMemoView.Memo.Clear;
117 | lfrxMemoView.Memo.Text := Format('Aplicativo de Exemplo: %s', ['VCL']);
118 | end;
119 | end).
120 | Execute; //PROCESSAMENTO DO RELATÓRIO/IMPRESSÃO
121 | except
122 | on E: Exception do
123 | begin
124 | if E is EFRPrinter then
125 | ShowMessage('Erro de impressão: ' + E.ToString)
126 | else
127 | ShowMessage('Erro de impressão: ' + E.Message);
128 | Exit;
129 | end;
130 | end;
131 |
132 | if lPrinted then
133 | ShowMessage('Impresso')
134 | else
135 | ShowMessage('Falha de impressão');
136 |
137 | end;
138 | ```
139 |
140 | **Observação**
141 |
142 | * Falta de memória pode gerar falha de impressão.
143 | * Impressão de documento grande pode ter demora na resposta de sucesso da impressão.
144 | * Windows Service Application é necessário configurar "logon" usando uma conta administrativa ou NT AUTHORITY\LocalService e ou NT AUTHORITY\NetworkService para uma impressão com sucesso.
145 | * IIS(ISAPI/CGI) devido a um [bug](https://blogs.stonesteps.ca/1/p/44) quando app 32 bits e Windows 64 bits não é possível imprimir, solução, compilar app 64 bits e com permissão usando uma conta NT AUTHORITY\LocalService e ou NT AUTHORITY\NetworkService.
146 |
147 | **Exemplo compilado**
148 |
149 | * VCL
150 | * VCL [(Horse)](https://github.com/HashLoad/horse)
151 |
152 | Download: [Demo.zip](https://github.com/antoniojmsjr/FastReportPrinter/files/9245293/Demo.zip)
153 |
154 |
155 |
156 | https://user-images.githubusercontent.com/20980984/183212903-ec64169a-f1f5-4c21-8c46-bc3e5a8c8078.mp4
157 |
158 |
159 |
160 | https://user-images.githubusercontent.com/20980984/183213069-68c4ca35-4804-481e-854e-e7d1ae303686.mp4
161 |
162 |
163 |
164 | **Teste de desempenho para aplicações web usando [JMeter](https://jmeter.apache.org/):**
165 |
166 | ```
167 | ..\FastReportPrinter\Samples\JMeter
168 | ```
169 |
170 |
171 | ## ⚠️ Licença
172 | `FastReportPrinter` is free and open-source software licensed under the [](https://github.com/antoniojmsjr/FastReportPrinter/blob/main/LICENSE)
173 |
--------------------------------------------------------------------------------
/Samples/CGI/CGI.dpr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/CGI/CGI.dpr
--------------------------------------------------------------------------------
/Samples/CGI/CGI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/CGI/CGI.res
--------------------------------------------------------------------------------
/Samples/CGI/Readme.txt:
--------------------------------------------------------------------------------
1 | Samples with Horse
2 |
3 | https://github.com/HashLoad/horse
--------------------------------------------------------------------------------
/Samples/Console/Console.dpr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/Console/Console.dpr
--------------------------------------------------------------------------------
/Samples/Console/Console.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/Console/Console.res
--------------------------------------------------------------------------------
/Samples/ConsoleHorse/ConsoleHorse.dpr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/ConsoleHorse/ConsoleHorse.dpr
--------------------------------------------------------------------------------
/Samples/ConsoleHorse/ConsoleHorse.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/ConsoleHorse/ConsoleHorse.res
--------------------------------------------------------------------------------
/Samples/ConsoleHorse/Readme.txt:
--------------------------------------------------------------------------------
1 | Samples with Horse
2 |
3 | https://github.com/HashLoad/horse
--------------------------------------------------------------------------------
/Samples/DB/FAST_REPORT_PRINTER.FDB:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/DB/FAST_REPORT_PRINTER.FDB
--------------------------------------------------------------------------------
/Samples/FMX/FMX.dpr:
--------------------------------------------------------------------------------
1 | program FMX;
2 |
3 | uses
4 | System.StartUpCopy,
5 | FMX.Forms,
6 | Main in 'Main.pas' {frmMain},
7 | Utils in '..\Utils\Utils.pas',
8 | Data in '..\Utils\Data.pas';
9 |
10 | {$R *.res}
11 |
12 | begin
13 | ReportMemoryLeaksOnShutdown := True;
14 | Application.Initialize;
15 | Application.CreateForm(TfrmMain, frmMain);
16 | Application.Run;
17 | end.
18 |
--------------------------------------------------------------------------------
/Samples/FMX/FMX.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/FMX/FMX.res
--------------------------------------------------------------------------------
/Samples/FMX/Main.fmx:
--------------------------------------------------------------------------------
1 | object frmMain: TfrmMain
2 | Left = 0
3 | Top = 0
4 | Caption = 'Impress'#227'o Fast Report'
5 | ClientHeight = 50
6 | ClientWidth = 500
7 | Position = ScreenCenter
8 | FormFactor.Width = 320
9 | FormFactor.Height = 480
10 | FormFactor.Devices = [Desktop]
11 | DesignerMasterStyle = 0
12 | object lytHeader: TLayout
13 | Align = Top
14 | Size.Width = 500.000000000000000000
15 | Size.Height = 50.000000000000000000
16 | Size.PlatformDefault = False
17 | TabOrder = 0
18 | object btnImprimir: TButton
19 | Position.X = 15.000000000000000000
20 | Position.Y = 15.000000000000000000
21 | TabOrder = 1
22 | Text = 'Imprimir'
23 | OnClick = btnImprimirClick
24 | end
25 | object btnImprimirThread: TButton
26 | Position.X = 369.000000000000000000
27 | Position.Y = 15.000000000000000000
28 | Size.Width = 120.000000000000000000
29 | Size.Height = 22.000000000000000000
30 | Size.PlatformDefault = False
31 | TabOrder = 0
32 | Text = 'Imprimir - Thread'
33 | OnClick = btnImprimirThreadClick
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/Samples/FMX/Main.pas:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antoniojmsjr/FastReportPrinter/fabe30dfd6f3881d4e814ecc9e299b1ccb2cff43/Samples/FMX/Main.pas
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Callback.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Callback;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | Generics.Collections, fpHTTP,
12 | {$ELSE}
13 | Web.HTTPApp, System.Generics.Collections,
14 | {$ENDIF}
15 | Horse.Request, Horse.Response, Horse.Proc, Horse.Commons;
16 |
17 | type
18 | {$IF DEFINED(FPC)}
19 | THorseCallbackRequest = procedure(AReq: THorseRequest);
20 | THorseCallbackResponse = procedure(ARes: THorseResponse);
21 | THorseCallbackRequestResponse = procedure(AReq: THorseRequest; ARes: THorseResponse);
22 | THorseCallback = procedure(AReq: THorseRequest; ARes: THorseResponse; ANext: TNextProc);
23 | TCallNextPath = function(var APath: TQueue; const AHTTPType: TMethodType; const ARequest: THorseRequest; const AResponse: THorseResponse): Boolean of object;
24 | {$ELSE}
25 | THorseCallbackRequest = reference to procedure(AReq: THorseRequest);
26 | THorseCallbackResponse = reference to procedure(ARes: THorseResponse);
27 | THorseCallbackRequestResponse = reference to procedure(AReq: THorseRequest; ARes: THorseResponse);
28 | THorseCallback = reference to procedure(AReq: THorseRequest; ARes: THorseResponse; ANext: TNextProc);
29 | TCallNextPath = reference to function(var APath: TQueue; const AHTTPType: TMethodType; const ARequest: THorseRequest; const AResponse: THorseResponse): Boolean;
30 | {$ENDIF}
31 |
32 | implementation
33 |
34 | end.
35 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Commons.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Commons;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$MODESWITCH TypeHelpers}
6 | {$ENDIF}
7 |
8 | interface
9 |
10 | uses
11 | {$IF DEFINED(FPC)}
12 | Classes, SysUtils, StrUtils
13 | {$ELSE}
14 | System.Classes, System.SysUtils
15 | {$ENDIF}
16 | ;
17 |
18 | type
19 | {$IF DEFINED(FPC)}
20 | TMethodType = (mtAny, mtGet, mtPut, mtPost, mtHead, mtDelete, mtPatch);
21 | {$ENDIF}
22 |
23 | {$SCOPEDENUMS ON}
24 | THTTPStatus = (
25 | Continue = 100,
26 | SwitchingProtocols = 101,
27 | Processing = 102,
28 | OK = 200,
29 | Created = 201,
30 | Accepted = 202,
31 | NonAuthoritativeInformation = 203,
32 | NoContent = 204,
33 | ResetContent = 205,
34 | PartialContent = 206,
35 | MultiStatus = 207,
36 | AlreadyReported = 208,
37 | IMUsed = 226,
38 | MultipleChoices = 300,
39 | MovedPermanently = 301,
40 | Found = 302,
41 | SeeOther = 303,
42 | NotModified = 304,
43 | UseProxy = 305,
44 | TemporaryRedirect = 307,
45 | PermanentRedirect = 308,
46 | BadRequest = 400,
47 | Unauthorized = 401,
48 | PaymentRequired = 402,
49 | Forbidden = 403,
50 | NotFound = 404,
51 | MethodNotAllowed = 405,
52 | NotAcceptable = 406,
53 | ProxyAuthenticationRequired = 407,
54 | RequestTimeout = 408,
55 | Conflict = 409,
56 | Gone = 410,
57 | LengthRequired = 411,
58 | PreconditionFailed = 412,
59 | PayloadTooLarge = 413,
60 | RequestURITooLong = 414,
61 | UnsupportedMediaType = 415,
62 | RequestedRangeNotSatisfiable = 416,
63 | ExpectationFailed = 417,
64 | Imateapot = 418,
65 | MisdirectedRequest = 421,
66 | UnprocessableEntity = 422,
67 | Locked = 423,
68 | FailedDependency = 424,
69 | UpgradeRequired = 426,
70 | PreconditionRequired = 428,
71 | TooManyRequests = 429,
72 | RequestHeaderFieldsTooLarge = 431,
73 | ConnectionClosedWithoutResponse = 444,
74 | UnavailableForLegalReasons = 451,
75 | ClientClosedRequest = 499,
76 | InternalServerError = 500,
77 | NotImplemented = 501,
78 | BadGateway = 502,
79 | ServiceUnavailable = 503,
80 | GatewayTimeout = 504,
81 | HTTPVersionNotSupported = 505,
82 | VariantAlsoNegotiates = 506,
83 | InsufficientStorage = 507,
84 | LoopDetected = 508,
85 | NotExtended = 510,
86 | NetworkAuthenticationRequired = 511,
87 | NetworkConnectTimeoutError = 599);
88 |
89 | TMimeTypes = (
90 | MultiPartFormData,
91 | ApplicationXWWWFormURLEncoded,
92 | ApplicationJSON,
93 | ApplicationOctetStream,
94 | ApplicationXML,
95 | ApplicationJavaScript,
96 | ApplicationPDF,
97 | ApplicationTypeScript,
98 | ApplicationZIP,
99 | TextPlain,
100 | TextCSS,
101 | TextCSV,
102 | TextHTML,
103 | ImageJPEG,
104 | ImagePNG,
105 | ImageGIF,
106 | Download);
107 |
108 | TMessageType = (Default, Error, Warning, Information);
109 | TLhsBracketsType = (Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual, Range, Like);
110 | {$SCOPEDENUMS OFF}
111 |
112 | TLhsBrackets = set of TLhsBracketsType;
113 |
114 | THTTPStatusHelper = {$IF DEFINED(FPC)} type {$ELSE} record {$ENDIF} helper for THTTPStatus
115 | function ToInteger: Integer;
116 | end;
117 |
118 | TMimeTypesHelper = {$IF DEFINED(FPC)} type {$ELSE} record {$ENDIF} helper for TMimeTypes
119 | function ToString: string;
120 | end;
121 |
122 | TLhsBracketsTypeHelper = {$IF DEFINED(FPC)} type {$ELSE} record {$ENDIF} helper for TLhsBracketsType
123 | function ToString: string;
124 | end;
125 |
126 | {$IF DEFINED(FPC)}
127 | function StringCommandToMethodType(const ACommand: string): TMethodType;
128 | {$ENDIF}
129 |
130 | implementation
131 |
132 | {$IF DEFINED(FPC)}
133 | function StringCommandToMethodType(const ACommand: string): TMethodType;
134 | begin
135 | case AnsiIndexText(ACommand, ['ANY', 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT']) of
136 | 0: Result := TMethodType.mtAny;
137 | 1: Result := TMethodType.mtDelete;
138 | 2: Result := TMethodType.mtGet;
139 | 3: Result := TMethodType.mtHead;
140 | 4: Result := TMethodType.mtPatch;
141 | 5: Result := TMethodType.mtPost;
142 | 6: Result := TMethodType.mtPut;
143 | end;
144 | end;
145 | {$ENDIF}
146 |
147 | { TLhsBracketsTypeHelper }
148 |
149 | function TLhsBracketsTypeHelper.ToString: string;
150 | begin
151 | case Self of
152 | TLhsBracketsType.Equal:
153 | Result := '[eq]';
154 | TLhsBracketsType.NotEqual:
155 | Result := '[ne]';
156 | TLhsBracketsType.LessThan:
157 | Result := '[lt]';
158 | TLhsBracketsType.LessThanOrEqual:
159 | Result := '[lte]';
160 | TLhsBracketsType.GreaterThan:
161 | Result := '[gt]';
162 | TLhsBracketsType.GreaterThanOrEqual:
163 | Result := '[gte]';
164 | TLhsBracketsType.Range:
165 | Result := '[range]';
166 | TLhsBracketsType.Like:
167 | Result := '[like]';
168 | end;
169 | end;
170 |
171 | { THTTPStatusHelper }
172 |
173 | function THTTPStatusHelper.ToInteger: Integer;
174 | begin
175 | Result := Ord(Self);
176 | end;
177 |
178 | { TMimeTypesHelper }
179 |
180 | function TMimeTypesHelper.ToString: string;
181 | begin
182 | case Self of
183 | TMimeTypes.MultiPartFormData:
184 | Result := 'multipart/form-data';
185 | TMimeTypes.ApplicationXWWWFormURLEncoded:
186 | Result := 'application/x-www-form-urlencoded';
187 | TMimeTypes.ApplicationJSON:
188 | Result := 'application/json';
189 | TMimeTypes.ApplicationOctetStream:
190 | Result := 'application/octet-stream';
191 | TMimeTypes.ApplicationXML:
192 | Result := 'application/xml';
193 | TMimeTypes.ApplicationJavaScript:
194 | Result := 'application/javascript';
195 | TMimeTypes.ApplicationPDF:
196 | Result := 'application/pdf';
197 | TMimeTypes.ApplicationTypeScript:
198 | Result := 'application/typescript';
199 | TMimeTypes.ApplicationZIP:
200 | Result := 'application/zip';
201 | TMimeTypes.TextPlain:
202 | Result := 'text/plain';
203 | TMimeTypes.TextCSS:
204 | Result := 'text/css';
205 | TMimeTypes.TextCSV:
206 | Result := 'text/csv';
207 | TMimeTypes.TextHTML:
208 | Result := 'text/html';
209 | TMimeTypes.ImageJPEG:
210 | Result := 'image/jpeg';
211 | TMimeTypes.ImagePNG:
212 | Result := 'image/png';
213 | TMimeTypes.ImageGIF:
214 | Result := 'image/gif';
215 | TMimeTypes.Download:
216 | Result := 'application/x-download';
217 | end;
218 | end;
219 |
220 | end.
221 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Constants.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Constants;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | const
10 | DEFAULT_HOST = '0.0.0.0';
11 | DEFAULT_PORT = 9000;
12 | START_RUNNING = 'Server is runing on %s:%d';
13 | HORSE_VERSION = '3.0.1';
14 |
15 | implementation
16 |
17 | end.
18 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.Group.Contract.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.Group.Contract;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses Horse.Core.Route.Contract, Horse.Core.RouterTree, Horse.Callback;
10 |
11 | type
12 | IHorseCoreGroup = interface
13 | ['{5EB734D6-6944-473E-9C79-506647E2F5E8}']
14 | function Prefix(const APrefix: string): IHorseCoreGroup;
15 | function Route(const APath: string): IHorseCoreRoute;
16 |
17 | function AddCallback(const ACallback: THorseCallback): IHorseCoreGroup;
18 | function AddCallbacks(const ACallbacks: TArray): IHorseCoreGroup;
19 |
20 | function Use(const ACallback: THorseCallback): IHorseCoreGroup; overload;
21 | function Use(const AMiddleware, ACallback: THorseCallback): IHorseCoreGroup; overload;
22 | function Use(const ACallbacks: array of THorseCallback): IHorseCoreGroup; overload;
23 | function Use(const ACallbacks: array of THorseCallback; const ACallback: THorseCallback): IHorseCoreGroup; overload;
24 |
25 | function Get(const APath: string; const ACallback: THorseCallback): IHorseCoreGroup; overload;
26 | function Get(const APath: string; const ACallback: THorseCallbackRequestResponse): IHorseCoreGroup; overload;
27 | function Get(const APath: string; const ACallback: THorseCallbackRequest): IHorseCoreGroup; overload;
28 | {$IFNDEF FPC}
29 | function Get(const APath: string; const ACallback: THorseCallbackResponse): IHorseCoreGroup; overload;
30 | {$IFEND}
31 |
32 | function Put(const APath: string; const ACallback: THorseCallback): IHorseCoreGroup; overload;
33 | function Put(const APath: string; const ACallback: THorseCallbackRequestResponse): IHorseCoreGroup; overload;
34 | function Put(const APath: string; const ACallback: THorseCallbackRequest): IHorseCoreGroup; overload;
35 | {$IFNDEF FPC}
36 | function Put(const APath: string; const ACallback: THorseCallbackResponse): IHorseCoreGroup; overload;
37 | {$IFEND}
38 |
39 | function Head(const APath: string; const ACallback: THorseCallback): IHorseCoreGroup; overload;
40 | function Head(const APath: string; const ACallback: THorseCallbackRequestResponse): IHorseCoreGroup; overload;
41 | function Head(const APath: string; const ACallback: THorseCallbackRequest): IHorseCoreGroup; overload;
42 | {$IFNDEF FPC}
43 | function Head(const APath: string; const ACallback: THorseCallbackResponse): IHorseCoreGroup; overload;
44 | {$IFEND}
45 |
46 | function Post(const APath: string; const ACallback: THorseCallback): IHorseCoreGroup; overload;
47 | function Post(const APath: string; const ACallback: THorseCallbackRequestResponse): IHorseCoreGroup; overload;
48 | function Post(const APath: string; const ACallback: THorseCallbackRequest): IHorseCoreGroup; overload;
49 | {$IFNDEF FPC}
50 | function Post(const APath: string; const ACallback: THorseCallbackResponse): IHorseCoreGroup; overload;
51 | {$IFEND}
52 |
53 | {$IF (defined(fpc) or (CompilerVersion > 27.0))}
54 | function Patch(const APath: string; const ACallback: THorseCallback): IHorseCoreGroup; overload;
55 | function Delete(const APath: string; const ACallback: THorseCallback): IHorseCoreGroup; overload;
56 |
57 | function Patch(const APath: string; const ACallback: THorseCallbackRequestResponse): IHorseCoreGroup; overload;
58 | function Patch(const APath: string; const ACallback: THorseCallbackRequest): IHorseCoreGroup; overload;
59 | {$IFNDEF FPC}
60 | function Patch(const APath: string; const ACallback: THorseCallbackResponse): IHorseCoreGroup; overload;
61 | {$IFEND}
62 |
63 | function Delete(const APath: string; const ACallback: THorseCallbackRequestResponse): IHorseCoreGroup; overload;
64 | function Delete(const APath: string; const ACallback: THorseCallbackRequest): IHorseCoreGroup; overload;
65 | {$IFNDEF FPC}
66 | function Delete(const APath: string; const ACallback: THorseCallbackResponse): IHorseCoreGroup; overload;
67 | {$IFEND}
68 | {$IFEND}
69 |
70 | function &End: T;
71 | end;
72 |
73 | implementation
74 |
75 | end.
76 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.Param.Config.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.Param.Config;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | type
10 |
11 | { THorseCoreParamConfig }
12 |
13 | THorseCoreParamConfig = class
14 | private
15 | class var FInstance: THorseCoreParamConfig;
16 | FRequiredMessage: string;
17 | FInvalidFormatMessage: string;
18 | FDateFormat: string;
19 | FTimeFormat: string;
20 | FReturnUTC: Boolean;
21 | FTrueValue: string;
22 | FCheckLhsBrackets: Boolean;
23 | constructor Create;
24 | public
25 | function RequiredMessage(const AValue: string): THorseCoreParamConfig; overload;
26 | function RequiredMessage: string; overload;
27 | function InvalidFormatMessage(const AValue: string): THorseCoreParamConfig; overload;
28 | function InvalidFormatMessage: string; overload;
29 | function DateFormat(const AValue: string): THorseCoreParamConfig; overload;
30 | function DateFormat: string; overload;
31 | function TimeFormat(const AValue: string): THorseCoreParamConfig; overload;
32 | function TimeFormat: string; overload;
33 | function ReturnUTC(const AValue: Boolean): THorseCoreParamConfig; overload;
34 | function ReturnUTC: Boolean; overload;
35 | function TrueValue(const AValue: string): THorseCoreParamConfig; overload;
36 | function TrueValue: string; overload;
37 | function CheckLhsBrackets(const AValue: Boolean): THorseCoreParamConfig; overload;
38 | function CheckLhsBrackets: Boolean; overload;
39 | class function GetInstance: THorseCoreParamConfig;
40 | class destructor UnInitialize;
41 | end;
42 |
43 | implementation
44 |
45 | uses
46 | {$IF DEFINED(FPC)}
47 | SysUtils;
48 | {$ELSE}
49 | System.SysUtils;
50 | {$ENDIF}
51 |
52 | constructor THorseCoreParamConfig.Create;
53 | begin
54 | FReturnUTC := True;
55 | FDateFormat := 'yyyy-MM-dd';
56 | FTimeFormat := 'hh:mm:ss';
57 | FTrueValue := 'true';
58 | FRequiredMessage := 'The %s param is required.';
59 | FInvalidFormatMessage := 'The %0:s param ''%1:s'' is not valid a %2:s type.';
60 | FCheckLhsBrackets := False;
61 | end;
62 |
63 | function THorseCoreParamConfig.DateFormat(const AValue: string): THorseCoreParamConfig;
64 | begin
65 | Result := Self;
66 | FDateFormat := AValue;
67 | end;
68 |
69 | function THorseCoreParamConfig.DateFormat: string;
70 | begin
71 | Result := FDateFormat;
72 | end;
73 |
74 | class function THorseCoreParamConfig.GetInstance: THorseCoreParamConfig;
75 | begin
76 | if not Assigned(FInstance) then
77 | FInstance := THorseCoreParamConfig.Create;
78 | Result := FInstance;
79 | end;
80 |
81 | function THorseCoreParamConfig.InvalidFormatMessage: string;
82 | begin
83 | Result := FInvalidFormatMessage;
84 | end;
85 |
86 | function THorseCoreParamConfig.InvalidFormatMessage(const AValue: string): THorseCoreParamConfig;
87 | begin
88 | Result := Self;
89 | FInvalidFormatMessage := AValue;
90 | end;
91 |
92 | function THorseCoreParamConfig.RequiredMessage(const AValue: string): THorseCoreParamConfig;
93 | begin
94 | Result := Self;
95 | FRequiredMessage := AValue;
96 | end;
97 |
98 | function THorseCoreParamConfig.RequiredMessage: string;
99 | begin
100 | Result := FRequiredMessage;
101 | end;
102 |
103 | function THorseCoreParamConfig.ReturnUTC(const AValue: Boolean): THorseCoreParamConfig;
104 | begin
105 | Result := Self;
106 | FReturnUTC := AValue;
107 | end;
108 |
109 | function THorseCoreParamConfig.ReturnUTC: Boolean;
110 | begin
111 | Result := FReturnUTC;
112 | end;
113 |
114 | function THorseCoreParamConfig.TimeFormat: string;
115 | begin
116 | Result := FTimeFormat;
117 | end;
118 |
119 | function THorseCoreParamConfig.TimeFormat(const AValue: string): THorseCoreParamConfig;
120 | begin
121 | Result := Self;
122 | FTimeFormat := AValue;
123 | end;
124 |
125 | function THorseCoreParamConfig.TrueValue(const AValue: string): THorseCoreParamConfig;
126 | begin
127 | Result := Self;
128 | FTrueValue := AValue;
129 | end;
130 |
131 | function THorseCoreParamConfig.TrueValue: string;
132 | begin
133 | Result := FTrueValue;
134 | end;
135 |
136 | function THorseCoreParamConfig.CheckLhsBrackets(const AValue: Boolean
137 | ): THorseCoreParamConfig;
138 | begin
139 | Result := Self;
140 | FCheckLhsBrackets := AValue;
141 | end;
142 |
143 | function THorseCoreParamConfig.CheckLhsBrackets: Boolean;
144 | begin
145 | Result := FCheckLhsBrackets;
146 | end;
147 |
148 | class destructor THorseCoreParamConfig.UnInitialize;
149 | begin
150 | if Assigned(FInstance) then
151 | FreeAndNil(FInstance);
152 | end;
153 |
154 | end.
155 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.Param.Field.Brackets.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.Param.Field.Brackets;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils, Classes,
12 | {$ELSE}
13 | System.SysUtils, System.Classes,
14 | {$ENDIF}
15 | Horse.Commons;
16 |
17 | type
18 | THorseCoreParamFieldLhsBrackets = class
19 | private
20 | FEq: string;
21 | FNe: string;
22 | FLt: string;
23 | FLte: string;
24 | FGt: string;
25 | FGte: string;
26 | FRange: string;
27 | FLike: string;
28 | FTypes: TLhsBrackets;
29 | public
30 | property Eq: string read Feq;
31 | property Ne: string read Fne;
32 | property Lt: string read Flt;
33 | property Lte: string read Flte;
34 | property Gt: string read Fgt;
35 | property Gte: string read Fgte;
36 | property Range: string read Frange;
37 | property Like: string read Flike;
38 | property Types: TLhsBrackets read FTypes write FTypes;
39 | procedure SetValue(const AType: TLhsBracketsType; const AValue: string);
40 | function GetValue(const AType: TLhsBracketsType): string;
41 | end;
42 |
43 | implementation
44 |
45 | procedure THorseCoreParamFieldLhsBrackets.SetValue(const AType: TLhsBracketsType; const AValue: string);
46 | begin
47 | case AType of
48 | TLhsBracketsType.Equal:
49 | FEq := AValue;
50 | TLhsBracketsType.NotEqual:
51 | FNe := AValue;
52 | TLhsBracketsType.LessThan:
53 | FLt := AValue;
54 | TLhsBracketsType.LessThanOrEqual:
55 | FLte := AValue;
56 | TLhsBracketsType.GreaterThan:
57 | FGt := AValue;
58 | TLhsBracketsType.GreaterThanOrEqual:
59 | FGte := AValue;
60 | TLhsBracketsType.Range:
61 | FRange := AValue;
62 | TLhsBracketsType.Like:
63 | FLike := AValue;
64 | end;
65 | end;
66 |
67 | function THorseCoreParamFieldLhsBrackets.GetValue(const AType: TLhsBracketsType): string;
68 | begin
69 | case AType of
70 | TLhsBracketsType.Equal:
71 | Result := FEq;
72 | TLhsBracketsType.NotEqual:
73 | Result := FNe;
74 | TLhsBracketsType.LessThan:
75 | Result := FLt;
76 | TLhsBracketsType.LessThanOrEqual:
77 | Result := FLte;
78 | TLhsBracketsType.GreaterThan:
79 | Result := FGt;
80 | TLhsBracketsType.GreaterThanOrEqual:
81 | Result := FGte;
82 | TLhsBracketsType.Range:
83 | Result := FRange;
84 | TLhsBracketsType.Like:
85 | Result := FLike;
86 | end;
87 | end;
88 |
89 | end.
90 |
91 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.Param.Header.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.Param.Header;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils, Classes, Generics.Collections, fpHTTP, fphttpserver, httpprotocol, HTTPDefs,
12 | {$ELSE}
13 | System.Classes, System.SysUtils, System.Generics.Collections,
14 | Web.HTTPApp, IdCustomHTTPServer, IdHeaderList, Horse.Rtti,
15 | {$ENDIF}
16 | Horse.Core.Param, Horse.Commons, Horse.Rtti.Helper;
17 |
18 | type
19 | THorseCoreParamHeader = class
20 | private
21 | class function GetHeadersList(const AWebRequest: {$IF DEFINED(FPC)}TRequest{$ELSE}TWebRequest{$ENDIF}): TStrings;
22 | public
23 | class function GetHeaders(const AWebRequest: {$IF DEFINED(FPC)}TRequest{$ELSE}TWebRequest{$ENDIF}): THorseList;
24 | end;
25 |
26 | implementation
27 |
28 | class function THorseCoreParamHeader.GetHeaders(const AWebRequest: {$IF DEFINED(FPC)}TRequest{$ELSE}TWebRequest{$ENDIF}): THorseList;
29 | var
30 | I: Integer;
31 | LName, LValue: string;
32 | LHeaders: TStrings;
33 | begin
34 | Result := THorseList.create;
35 | try
36 | LHeaders := GetHeadersList(AWebRequest);
37 | try
38 | for I := 0 to Pred(LHeaders.Count) do
39 | begin
40 | LName := LHeaders.Names[I];
41 | LValue := LHeaders.Values[LName];
42 | Result.AddOrSetValue(LName, Trim(LValue));
43 | end;
44 | {$IF DEFINED(FPC)}
45 | for I := Integer(Low(THeader)) to Integer(High(THeader)) do
46 | begin
47 | LName := HTTPHeaderNames[THeader(I)];
48 | LValue := AWebRequest.GetHeader(THeader(I));
49 | if not LValue.Trim.IsEmpty then
50 | Result.AddOrSetValue(LName, LValue);
51 | end;
52 | {$ENDIF}
53 | finally
54 | LHeaders.Free;
55 | end;
56 | except
57 | Result.Free;
58 | raise;
59 | end;
60 | end;
61 |
62 | class function THorseCoreParamHeader.GetHeadersList(const AWebRequest: {$IF DEFINED(FPC)}TRequest{$ELSE}TWebRequest{$ENDIF}): TStrings;
63 | {$IF NOT DEFINED(HORSE_ISAPI)}
64 | var
65 | LRequest: {$IF DEFINED(FPC)} TFPHTTPConnectionRequest {$ELSE} TIdHTTPRequestInfo {$ENDIF};
66 | {$IF NOT DEFINED(FPC)}
67 | LObject: TObject;
68 | {$ENDIF}
69 | {$ENDIF}
70 | begin
71 | Result := TStringList.Create;
72 | try
73 | Result.NameValueSeparator := ':';
74 | {$IF DEFINED(FPC)}
75 | if AWebRequest is TFPHTTPConnectionRequest then
76 | begin
77 | LRequest := TFPHTTPConnectionRequest(AWebRequest);
78 | Result.NameValueSeparator := '=';
79 | Result.Text := LRequest.CustomHeaders.Text;
80 | end;
81 | {$ELSEIF DEFINED(HORSE_ISAPI)}
82 | Result.Text := AWebRequest.GetFieldByName('ALL_RAW');
83 | {$ELSE}
84 | LObject := THorseRtti.GetInstance.GetType(AWebRequest.ClassType).FieldValueAsObject(AWebRequest, 'FRequestInfo');
85 | if (Assigned(LObject)) and (LObject is TIdHTTPRequestInfo) then
86 | begin
87 | LRequest := TIdHTTPRequestInfo(LObject);
88 | Result.Text := LRequest.RawHeaders.Text;
89 | end;
90 | {$ENDIF}
91 | except
92 | Result.Free;
93 | raise;
94 | end;
95 | end;
96 |
97 | end.
98 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.Param.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.Param;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils, Classes, DateUtils, Generics.Collections, fpHTTP, fphttpserver, HTTPDefs,
12 | {$ELSE}
13 | System.SysUtils, System.Classes, System.DateUtils, System.Generics.Collections,
14 | {$ENDIF}
15 | Horse.Exception, Horse.Commons, Horse.Core.Param.Field;
16 |
17 | type
18 | THorseList = TDictionary;
19 |
20 | THorseCoreParam = class
21 | private
22 | FParams: THorseList;
23 | FFiles: TDictionary;
24 | FFields: TDictionary;
25 | FContent: TStrings;
26 | FRequired: Boolean;
27 | function GetItem(const AKey: string): string;
28 | function GetDictionary: THorseList;
29 | function GetCount: Integer;
30 | function GetContent: TStrings;
31 | function AsString(const AKey: string): string;
32 | procedure ClearFields;
33 |
34 | function NewField(const AKey: String): THorseCoreParamField;
35 | public
36 | function Required(const AValue: Boolean): THorseCoreParam;
37 | function Field(const AKey: string): THorseCoreParamField;
38 | function ContainsKey(const AKey: string): Boolean;
39 | function ContainsValue(const AValue: string): Boolean;
40 | function ToArray: TArray>;
41 | function TryGetValue(const AKey: string; var AValue: string): Boolean;
42 | property Content: TStrings read GetContent;
43 | property Count: Integer read GetCount;
44 | property Items[const AKey: string]: string read GetItem; default;
45 | property Dictionary: THorseList read GetDictionary;
46 |
47 | function AddStream(const AKey: string; const AContent: TStream): THorseCoreParam;
48 | constructor Create(const AParams: THorseList);
49 | destructor Destroy; override;
50 | end;
51 |
52 | implementation
53 |
54 | uses Horse.Core.Param.Config;
55 |
56 | function THorseCoreParam.ContainsKey(const AKey: string): Boolean;
57 | var
58 | LKey: string;
59 | begin
60 | Result := False;
61 | for LKey in FParams.Keys do
62 | begin
63 | if AnsiCompareText(LKey, AKey) = 0 then
64 | Exit(True);
65 | end;
66 | end;
67 |
68 | function THorseCoreParam.ContainsValue(const AValue: string): Boolean;
69 | begin
70 | Result := FParams.ContainsValue(AValue);
71 | end;
72 |
73 | constructor THorseCoreParam.Create(const AParams: THorseList);
74 | begin
75 | FParams := AParams;
76 | FRequired := False;
77 | end;
78 |
79 | destructor THorseCoreParam.Destroy;
80 | begin
81 | FParams.Free;
82 | FContent.Free;
83 | ClearFields;
84 | if Assigned(FFiles) then
85 | FFiles.Free;
86 | inherited;
87 | end;
88 |
89 | function THorseCoreParam.Field(const AKey: string): THorseCoreParamField;
90 | var
91 | LFieldName: string;
92 | begin
93 | if not Assigned(FFields) then
94 | FFields := TDictionary.Create;
95 |
96 | LFieldName := AKey.ToLower;
97 | if FFields.ContainsKey(LFieldName) then
98 | Exit(FFields.Items[LFieldName]);
99 |
100 | Result := NewField(AKey);
101 | try
102 | Result
103 | .Required(FRequired)
104 | .DateFormat(THorseCoreParamConfig.GetInstance.DateFormat)
105 | .InvalidFormatMessage(THorseCoreParamConfig.GetInstance.InvalidFormatMessage)
106 | .RequiredMessage(THorseCoreParamConfig.GetInstance.RequiredMessage)
107 | .ReturnUTC(THorseCoreParamConfig.GetInstance.ReturnUTC)
108 | .TimeFormat(THorseCoreParamConfig.GetInstance.TimeFormat)
109 | .TrueValue(THorseCoreParamConfig.GetInstance.TrueValue);
110 |
111 | FFields.AddOrSetValue(LFieldName, Result);
112 | except
113 | Result.Free;
114 | raise;
115 | end;
116 | end;
117 |
118 | function THorseCoreParam.AddStream(const AKey: string; const AContent: TStream): THorseCoreParam;
119 | begin
120 | Result := Self;
121 | if not Assigned(FFiles) then
122 | FFiles := TDictionary.Create;
123 |
124 | FFiles.AddOrSetValue(AKey, AContent);
125 | end;
126 |
127 | function THorseCoreParam.AsString(const AKey: string): string;
128 | var
129 | LKey: string;
130 | begin
131 | Result := EmptyStr;
132 | for LKey in FParams.Keys do
133 | begin
134 | if AnsiCompareText(LKey, AKey) = 0 then
135 | Exit(FParams.Items[LKey]);
136 | end;
137 | end;
138 |
139 | procedure THorseCoreParam.ClearFields;
140 | var
141 | LKey: string;
142 | begin
143 | if Assigned(FFields) then
144 | begin
145 | for LKey in FFields.Keys do
146 | FFields.Items[LKey].Free;
147 |
148 | FFields.Free;
149 | end;
150 | end;
151 |
152 | function THorseCoreParam.GetContent: TStrings;
153 | var
154 | LKey: string;
155 | begin
156 | if not Assigned(FContent) then
157 | begin
158 | FContent := TstringList.Create;
159 | for LKey in FParams.Keys do
160 | FContent.Add(Format('%s=%s', [LKey, FParams[LKey]]));
161 | end;
162 | Result := FContent;
163 | end;
164 |
165 | function THorseCoreParam.GetCount: Integer;
166 | begin
167 | Result := FParams.Count;
168 | end;
169 |
170 | function THorseCoreParam.GetItem(const AKey: string): string;
171 | var
172 | LKey: string;
173 | begin
174 | for LKey in FParams.Keys do
175 | begin
176 | if AnsiCompareText(LKey, AKey) = 0 then
177 | Exit(FParams[LKey]);
178 | end;
179 | Result := EmptyStr;
180 | end;
181 |
182 | function THorseCoreParam.NewField(const AKey: String): THorseCoreParamField;
183 | var
184 | LKey: String;
185 | begin
186 | if Assigned(FFiles) then
187 | begin
188 | for LKey in FFiles.Keys do
189 | begin
190 | if AnsiSameText(LKey, AKey) then
191 | begin
192 | Result := THorseCoreParamField.Create(FFiles.Items[LKey], AKey);
193 | Exit;
194 | end;
195 | end;
196 | end;
197 |
198 | Result := THorseCoreParamField.create(FParams, AKey);
199 | end;
200 |
201 | function THorseCoreParam.Required(const AValue: Boolean): THorseCoreParam;
202 | begin
203 | Result := Self;
204 | FRequired := AValue;
205 | end;
206 |
207 | function THorseCoreParam.GetDictionary: THorseList;
208 | begin
209 | Result := FParams;
210 | end;
211 |
212 | function THorseCoreParam.ToArray: TArray>;
213 | begin
214 | Result := FParams.ToArray;
215 | end;
216 |
217 | function THorseCoreParam.TryGetValue(const AKey: string; var AValue: string): Boolean;
218 | begin
219 | Result := ContainsKey(AKey);
220 | if Result then
221 | AValue := AsString(AKey);
222 | end;
223 |
224 | end.
225 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.Route.Contract.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.Route.Contract;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses Horse.Core.RouterTree, Horse.Callback;
10 |
11 | type
12 | IHorseCoreRoute = interface
13 | ['{8D593D98-44B3-4FD2-A21B-BA29F784B3AA}']
14 | function AddCallback(const ACallback: THorseCallback): IHorseCoreRoute;
15 | function AddCallbacks(const ACallbacks: TArray): IHorseCoreRoute;
16 |
17 | function All(const ACallback: THorseCallback): IHorseCoreRoute; overload;
18 | function All(const AMiddleware, ACallback: THorseCallback): IHorseCoreRoute; overload;
19 | function All(const ACallbacks: array of THorseCallback): IHorseCoreRoute; overload;
20 | function All(const ACallbacks: array of THorseCallback; const ACallback: THorseCallback): IHorseCoreRoute; overload;
21 |
22 | function Get(const ACallback: THorseCallback): IHorseCoreRoute; overload;
23 | function Get(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
24 | function Get(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
25 | {$IFNDEF FPC}
26 | function Get(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
27 | {$IFEND}
28 |
29 | function Put(const ACallback: THorseCallback): IHorseCoreRoute; overload;
30 | function Put(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
31 | function Put(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
32 | {$IFNDEF FPC}
33 | function Put(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
34 | {$IFEND}
35 |
36 | function Head(const ACallback: THorseCallback): IHorseCoreRoute; overload;
37 | function Head(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
38 | function Head(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
39 | {$IFNDEF FPC}
40 | function Head(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
41 | {$IFEND}
42 |
43 | function Post(const ACallback: THorseCallback): IHorseCoreRoute; overload;
44 | function Post(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
45 | function Post(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
46 | {$IFNDEF FPC}
47 | function Post(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
48 | {$IFEND}
49 |
50 | {$IF (DEFINED(FPC) OR (CompilerVersion > 27.0))}
51 | function Patch(const ACallback: THorseCallback): IHorseCoreRoute; overload;
52 | function Delete(const ACallback: THorseCallback): IHorseCoreRoute; overload;
53 |
54 | function Patch(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
55 | function Patch(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
56 | {$IFNDEF FPC}
57 | function Patch(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
58 | {$IFEND}
59 |
60 | function Delete(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
61 | function Delete(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
62 | {$IFNDEF FPC}
63 | function Delete(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
64 | {$IFEND}
65 | {$IFEND}
66 |
67 | function &End: T;
68 | end;
69 |
70 | implementation
71 |
72 | end.
73 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.Route.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.Route;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils,
12 | {$ELSE}
13 | System.SysUtils,
14 | {$ENDIF}
15 | Horse.Core.Route.Contract, Horse.Core.RouterTree, Horse.Callback;
16 |
17 | type
18 | THorseCoreRoute = class(TInterfacedObject, IHorseCoreRoute)
19 | private
20 | FPath: string;
21 | FHorseCore: TObject;
22 | public
23 | constructor Create(const APath: string);
24 |
25 | function This: IHorseCoreRoute;
26 | function AddCallback(const ACallback: THorseCallback): IHorseCoreRoute;
27 | function AddCallbacks(const ACallbacks: TArray): IHorseCoreRoute;
28 |
29 | function All(const ACallback: THorseCallback): IHorseCoreRoute; overload;
30 | function All(const AMiddleware, ACallback: THorseCallback): IHorseCoreRoute; overload;
31 | function All(const ACallbacks: array of THorseCallback): IHorseCoreRoute; overload;
32 | function All(const ACallbacks: array of THorseCallback; const ACallback: THorseCallback): IHorseCoreRoute; overload;
33 |
34 | function Get(const ACallback: THorseCallback): IHorseCoreRoute; overload;
35 | function Get(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
36 | function Get(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
37 | {$IFNDEF FPC}
38 | function Get(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
39 | {$IFEND}
40 |
41 | function Put(const ACallback: THorseCallback): IHorseCoreRoute; overload;
42 | function Put(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
43 | function Put(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
44 | {$IFNDEF FPC}
45 | function Put(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
46 | {$IFEND}
47 |
48 | function Head(const ACallback: THorseCallback): IHorseCoreRoute; overload;
49 | function Head(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
50 | function Head(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
51 | {$IFNDEF FPC}
52 | function Head(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
53 | {$IFEND}
54 |
55 | function Post(const ACallback: THorseCallback): IHorseCoreRoute; overload;
56 | function Post(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
57 | function Post(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
58 | {$IFNDEF FPC}
59 | function Post(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
60 | {$IFEND}
61 |
62 | {$IF (DEFINED(FPC) OR (CompilerVersion > 27.0))}
63 | function Patch(const ACallback: THorseCallback): IHorseCoreRoute; overload;
64 | function Delete(const ACallback: THorseCallback): IHorseCoreRoute; overload;
65 |
66 | function Patch(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
67 | function Patch(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
68 | {$IFNDEF FPC}
69 | function Patch(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
70 | {$IFEND}
71 |
72 | function Delete(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute; overload;
73 | function Delete(const ACallback: THorseCallbackRequest): IHorseCoreRoute; overload;
74 | {$IFNDEF FPC}
75 | function Delete(const ACallback: THorseCallbackResponse): IHorseCoreRoute; overload;
76 | {$IFEND}
77 | {$IFEND}
78 |
79 | function &End: T;
80 | end;
81 |
82 | implementation
83 |
84 | uses Horse.Core;
85 |
86 | constructor THorseCoreRoute.Create(const APath: string);
87 | begin
88 | FPath := APath;
89 | FHorseCore := THorseCore.GetInstance;
90 | end;
91 |
92 | function THorseCoreRoute.This: IHorseCoreRoute;
93 | begin
94 | Result := Self;
95 | end;
96 |
97 | function THorseCoreRoute.All(const ACallback: THorseCallback): IHorseCoreRoute;
98 | begin
99 | Result := Self;
100 | THorseCore(FHorseCore).Use(FPath, ACallback);
101 | end;
102 |
103 | function THorseCoreRoute.All(const AMiddleware, ACallback: THorseCallback): IHorseCoreRoute;
104 | begin
105 | Result := Self;
106 | THorseCore(FHorseCore).Use(FPath, [AMiddleware, ACallback]);
107 | end;
108 |
109 | function THorseCoreRoute.All(const ACallbacks: array of THorseCallback): IHorseCoreRoute;
110 | begin
111 | Result := Self;
112 | THorseCore(FHorseCore).Use(FPath, ACallbacks);
113 | end;
114 |
115 | function THorseCoreRoute.&End: T;
116 | begin
117 | Result := FHorseCore as T;
118 | end;
119 |
120 | function THorseCoreRoute.AddCallback(const ACallback: THorseCallback): IHorseCoreRoute;
121 | begin
122 | Result := Self;
123 | THorseCore(FHorseCore).AddCallback(ACallback);
124 | end;
125 |
126 | function THorseCoreRoute.All(const ACallbacks: array of THorseCallback; const ACallback: THorseCallback): IHorseCoreRoute;
127 | begin
128 | Result := Self;
129 | THorseCore(FHorseCore).Use(FPath, ACallbacks);
130 | THorseCore(FHorseCore).Use(FPath, [ACallback]);
131 | end;
132 |
133 | {$IF (DEFINED(FPC) OR (CompilerVersion > 27.0))}
134 | function THorseCoreRoute.Delete(const ACallback: THorseCallback): IHorseCoreRoute;
135 | begin
136 | Result := Self;
137 | THorseCore(FHorseCore).Delete(FPath, ACallback);
138 | end;
139 |
140 | function THorseCoreRoute.Patch(const ACallback: THorseCallback): IHorseCoreRoute;
141 | begin
142 | Result := Self;
143 | THorseCore(FHorseCore).Patch(FPath, ACallback);
144 | end;
145 |
146 | function THorseCoreRoute.Delete(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute;
147 | begin
148 | THorseCore(FHorseCore).Delete(FPath, ACallback);
149 | Result := Self;
150 | end;
151 |
152 | function THorseCoreRoute.Delete(const ACallback: THorseCallbackRequest): IHorseCoreRoute;
153 | begin
154 | THorseCore(FHorseCore).Delete(FPath, ACallback);
155 | Result := Self;
156 | end;
157 |
158 | {$IFNDEF FPC}
159 | function THorseCoreRoute.Delete(const ACallback: THorseCallbackResponse): IHorseCoreRoute;
160 | begin
161 | THorseCore(FHorseCore).Delete(FPath, ACallback);
162 | Result := Self;
163 | end;
164 | {$IFEND}
165 |
166 | function THorseCoreRoute.Patch(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute;
167 | begin
168 | THorseCore(FHorseCore).Patch(FPath, ACallback);
169 | Result := Self;
170 | end;
171 |
172 | function THorseCoreRoute.Patch(const ACallback: THorseCallbackRequest): IHorseCoreRoute;
173 | begin
174 | THorseCore(FHorseCore).Patch(FPath, ACallback);
175 | Result := Self;
176 | end;
177 |
178 | {$IFNDEF FPC}
179 | function THorseCoreRoute.Patch(const ACallback: THorseCallbackResponse): IHorseCoreRoute;
180 | begin
181 | THorseCore(FHorseCore).Patch(FPath, ACallback);
182 | Result := Self;
183 | end;
184 | {$IFEND}
185 | {$IFEND}
186 |
187 | function THorseCoreRoute.Get(const ACallback: THorseCallback): IHorseCoreRoute;
188 | begin
189 | Result := Self;
190 | THorseCore(FHorseCore).Get(FPath, ACallback);
191 | end;
192 |
193 | function THorseCoreRoute.Head(const ACallback: THorseCallback): IHorseCoreRoute;
194 | begin
195 | Result := Self;
196 | THorseCore(FHorseCore).Head(FPath, ACallback);
197 | end;
198 |
199 | function THorseCoreRoute.Post(const ACallback: THorseCallback): IHorseCoreRoute;
200 | begin
201 | Result := Self;
202 | THorseCore(FHorseCore).Post(FPath, ACallback);
203 | end;
204 |
205 | function THorseCoreRoute.Put(const ACallback: THorseCallback): IHorseCoreRoute;
206 | begin
207 | Result := Self;
208 | THorseCore(FHorseCore).Put(FPath, ACallback);
209 | end;
210 |
211 | function THorseCoreRoute.AddCallbacks(const ACallbacks: TArray): IHorseCoreRoute;
212 | var
213 | LCallback: THorseCallback;
214 | begin
215 | for LCallback in ACallbacks do
216 | AddCallback(LCallback);
217 | Result := Self;
218 | end;
219 |
220 | function THorseCoreRoute.Get(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute;
221 | begin
222 | THorseCore(FHorseCore).Get(FPath, ACallback);
223 | Result := Self;
224 | end;
225 |
226 | function THorseCoreRoute.Get(const ACallback: THorseCallbackRequest): IHorseCoreRoute;
227 | begin
228 | THorseCore(FHorseCore).Get(FPath, ACallback);
229 | Result := Self;
230 | end;
231 |
232 | {$IFNDEF FPC}
233 | function THorseCoreRoute.Get(const ACallback: THorseCallbackResponse): IHorseCoreRoute;
234 | begin
235 | THorseCore(FHorseCore).Get(FPath, ACallback);
236 | Result := Self;
237 | end;
238 | {$IFEND}
239 |
240 | function THorseCoreRoute.Head(const ACallback: THorseCallbackRequest): IHorseCoreRoute;
241 | begin
242 | THorseCore(FHorseCore).Head(FPath, ACallback);
243 | Result := Self;
244 | end;
245 |
246 | function THorseCoreRoute.Head(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute;
247 | begin
248 | THorseCore(FHorseCore).Head(FPath, ACallback);
249 | Result := Self;
250 | end;
251 |
252 | {$IFNDEF FPC}
253 | function THorseCoreRoute.Head(const ACallback: THorseCallbackResponse): IHorseCoreRoute;
254 | begin
255 | THorseCore(FHorseCore).Head(FPath, ACallback);
256 | Result := Self;
257 | end;
258 | {$IFEND}
259 |
260 | function THorseCoreRoute.Post(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute;
261 | begin
262 | THorseCore(FHorseCore).Post(FPath, ACallback);
263 | Result := Self;
264 | end;
265 |
266 | function THorseCoreRoute.Post(const ACallback: THorseCallbackRequest): IHorseCoreRoute;
267 | begin
268 | THorseCore(FHorseCore).Post(FPath, ACallback);
269 | Result := Self;
270 | end;
271 |
272 | {$IFNDEF FPC}
273 | function THorseCoreRoute.Post(const ACallback: THorseCallbackResponse): IHorseCoreRoute;
274 | begin
275 | THorseCore(FHorseCore).Post(FPath, ACallback);
276 | Result := Self;
277 | end;
278 | {$IFEND}
279 |
280 | {$IFNDEF FPC}
281 | function THorseCoreRoute.Put(const ACallback: THorseCallbackResponse): IHorseCoreRoute;
282 | begin
283 | THorseCore(FHorseCore).Put(FPath, ACallback);
284 | Result := Self;
285 | end;
286 | {$IFEND}
287 |
288 | function THorseCoreRoute.Put(const ACallback: THorseCallbackRequest): IHorseCoreRoute;
289 | begin
290 | THorseCore(FHorseCore).Put(FPath, ACallback);
291 | Result := Self;
292 | end;
293 |
294 | function THorseCoreRoute.Put(const ACallback: THorseCallbackRequestResponse): IHorseCoreRoute;
295 | begin
296 | THorseCore(FHorseCore).Put(FPath, ACallback);
297 | Result := Self;
298 | end;
299 |
300 | end.
301 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.RouterTree.NextCaller.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.RouterTree.NextCaller;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils, Generics.Collections, fpHTTP, httpprotocol,
12 | {$ELSE}
13 | System.NetEncoding, System.SysUtils, Web.HTTPApp, System.Generics.Collections,
14 | {$ENDIF}
15 | Horse.Commons, Horse.Request, Horse.Response, Horse.Callback;
16 |
17 | type
18 | TNextCaller = class
19 | private
20 | FIndex: Integer;
21 | FIndexCallback: Integer;
22 | FPath: TQueue;
23 | FHTTPType: TMethodType;
24 | FRequest: THorseRequest;
25 | FResponse: THorseResponse;
26 | FMiddleware: TList;
27 | FCallBack: TObjectDictionary>;
28 | FCallNextPath: TCallNextPath;
29 | FIsGroup: Boolean;
30 | FTag: string;
31 | FIsRegex: Boolean;
32 | FFound: ^Boolean;
33 | public
34 | function Init: TNextCaller;
35 | function SetCallback(const ACallback: TObjectDictionary>): TNextCaller;
36 | function SetPath(const APath: TQueue): TNextCaller;
37 | function SetHTTPType(const AHTTPType: TMethodType): TNextCaller;
38 | function SetRequest(const ARequest: THorseRequest): TNextCaller;
39 | function SetResponse(const AResponse: THorseResponse): TNextCaller;
40 | function SetIsGroup(const AIsGroup: Boolean): TNextCaller;
41 | function SetMiddleware(const AMiddleware: TList): TNextCaller;
42 | function SetTag(const ATag: string): TNextCaller;
43 | function SetIsRegex(const AIsRegex: Boolean): TNextCaller;
44 | function SetOnCallNextPath(const ACallNextPath: TCallNextPath): TNextCaller;
45 | function SetFound(var AFound: Boolean): TNextCaller;
46 | procedure Next;
47 | end;
48 |
49 | implementation
50 |
51 | uses Horse.Exception, Horse.Exception.Interrupted;
52 |
53 | function TNextCaller.Init: TNextCaller;
54 | var
55 | LCurrent: string;
56 | begin
57 | Result := Self;
58 | if not FIsGroup then
59 | LCurrent := FPath.Dequeue;
60 | FIndex := -1;
61 | FIndexCallback := -1;
62 | if FIsRegex then
63 | FRequest.Params.Dictionary.Add(FTag, {$IF DEFINED(FPC)}HTTPDecode(LCurrent){$ELSE}TNetEncoding.URL.Decode(LCurrent){$ENDIF});
64 | end;
65 |
66 | procedure TNextCaller.Next;
67 | var
68 | LCallback: TList;
69 | begin
70 | inc(FIndex);
71 | if (FMiddleware.Count > FIndex) then
72 | begin
73 | FFound^ := True;
74 | Self.FMiddleware.Items[FIndex](FRequest, FResponse, Next);
75 | if (FMiddleware.Count > FIndex) then
76 | Next;
77 | end
78 | else
79 | if (FPath.Count = 0) and assigned(FCallBack) then
80 | begin
81 | inc(FIndexCallback);
82 | if FCallBack.TryGetValue(FHTTPType, LCallback) then
83 | begin
84 | if (LCallback.Count > FIndexCallback) then
85 | begin
86 | try
87 | FFound^ := True;
88 | LCallback.Items[FIndexCallback](FRequest, FResponse, Next);
89 | except
90 | on E: Exception do
91 | begin
92 | if (not(E is EHorseCallbackInterrupted)) and
93 | (not(E is EHorseException)) and
94 | (FResponse.Status < Integer(THTTPStatus.BadRequest))
95 | then
96 | FResponse.Send('Internal Application Error').Status(THTTPStatus.InternalServerError);
97 | raise;
98 | end;
99 | end;
100 | Next;
101 | end;
102 | end
103 | else
104 | begin
105 | if FCallBack.Count > 0 then
106 | begin
107 | FFound^ := True;
108 | FResponse.Send('Method Not Allowed').Status(THTTPStatus.MethodNotAllowed);
109 | end
110 | else
111 | FResponse.Send('Not Found').Status(THTTPStatus.NotFound)
112 | end;
113 | end
114 | else
115 | FFound^ := FCallNextPath(FPath, FHTTPType, FRequest, FResponse);
116 |
117 | if not FFound^ then
118 | FResponse.Send('Not Found').Status(THTTPStatus.NotFound);
119 | end;
120 |
121 | function TNextCaller.SetCallback(const ACallback: TObjectDictionary < TMethodType, TList < THorseCallback >> ): TNextCaller;
122 | begin
123 | FCallBack := ACallback;
124 | Result := Self;
125 | end;
126 |
127 | function TNextCaller.SetFound(var AFound: Boolean): TNextCaller;
128 | begin
129 | FFound := @AFound;
130 | Result := Self;
131 | end;
132 |
133 | function TNextCaller.SetHTTPType(const AHTTPType: TMethodType): TNextCaller;
134 | begin
135 | FHTTPType := AHTTPType;
136 | Result := Self;
137 | end;
138 |
139 | function TNextCaller.SetIsGroup(const AIsGroup: Boolean): TNextCaller;
140 | begin
141 | FIsGroup := AIsGroup;
142 | Result := Self;
143 | end;
144 |
145 | function TNextCaller.SetIsRegex(const AIsRegex: Boolean): TNextCaller;
146 | begin
147 | FIsRegex := AIsRegex;
148 | Result := Self;
149 | end;
150 |
151 | function TNextCaller.SetMiddleware(const AMiddleware: TList): TNextCaller;
152 | begin
153 | FMiddleware := AMiddleware;
154 | Result := Self;
155 | end;
156 |
157 | function TNextCaller.SetOnCallNextPath(const ACallNextPath: TCallNextPath): TNextCaller;
158 | begin
159 | FCallNextPath := ACallNextPath;
160 | Result := Self;
161 | end;
162 |
163 | function TNextCaller.SetPath(const APath: TQueue): TNextCaller;
164 | begin
165 | FPath := APath;
166 | Result := Self;
167 | end;
168 |
169 | function TNextCaller.SetRequest(const ARequest: THorseRequest): TNextCaller;
170 | begin
171 | FRequest := ARequest;
172 | Result := Self;
173 | end;
174 |
175 | function TNextCaller.SetResponse(const AResponse: THorseResponse): TNextCaller;
176 | begin
177 | FResponse := AResponse;
178 | Result := Self;
179 | end;
180 |
181 | function TNextCaller.SetTag(const ATag: string): TNextCaller;
182 | begin
183 | FTag := ATag;
184 | Result := Self;
185 | end;
186 |
187 | end.
188 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Core.RouterTree.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Core.RouterTree;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils, Generics.Collections, fpHTTP, httpprotocol,
12 | {$ELSE}
13 | System.SysUtils, System.NetEncoding, Web.HTTPApp, System.Generics.Collections,
14 | {$ENDIF}
15 | Horse.Request, Horse.Response, Horse.Proc, Horse.Commons, Horse.Callback;
16 |
17 | type
18 | PHorseRouterTree = ^THorseRouterTree;
19 |
20 | THorseRouterTree = class
21 | strict private
22 | FPrefix: string;
23 | FIsInitialized: Boolean;
24 | function GetQueuePath(APath: string; const AUsePrefix: Boolean = True): TQueue;
25 | function ForcePath(const APath: string): THorseRouterTree;
26 | private
27 | FPart: string;
28 | FTag: string;
29 | FIsRegex: Boolean;
30 | FMiddleware: TList;
31 | FRegexedKeys: TList;
32 | FCallBack: TObjectDictionary>;
33 | FRoute: TObjectDictionary;
34 | procedure RegisterInternal(const AHTTPType: TMethodType; var APath: TQueue; const ACallback: THorseCallback);
35 | procedure RegisterMiddlewareInternal(var APath: TQueue; const AMiddleware: THorseCallback);
36 | function ExecuteInternal(const APath: TQueue; const AHTTPType: TMethodType; const ARequest: THorseRequest; const AResponse: THorseResponse; const AIsGroup: Boolean = False): Boolean;
37 | function CallNextPath(var APath: TQueue; const AHTTPType: TMethodType; const ARequest: THorseRequest; const AResponse: THorseResponse): Boolean;
38 | function HasNext(const AMethod: TMethodType; const APaths: TArray; AIndex: Integer = 0): Boolean;
39 | public
40 | function CreateRouter(const APath: string): THorseRouterTree;
41 | function GetPrefix: string;
42 | procedure Prefix(const APrefix: string);
43 | procedure RegisterRoute(const AHTTPType: TMethodType; const APath: string; const ACallback: THorseCallback);
44 | procedure RegisterMiddleware(const APath: string; const AMiddleware: THorseCallback); overload;
45 | procedure RegisterMiddleware(const AMiddleware: THorseCallback); overload;
46 | function Execute(const ARequest: THorseRequest; const AResponse: THorseResponse): Boolean;
47 | constructor Create;
48 | destructor Destroy; override;
49 | end;
50 |
51 | implementation
52 |
53 | uses Horse.Exception, Horse.Core.RouterTree.NextCaller;
54 |
55 | procedure THorseRouterTree.RegisterRoute(const AHTTPType: TMethodType; const APath: string; const ACallback: THorseCallback);
56 | var
57 | LPathChain: TQueue;
58 | begin
59 | LPathChain := GetQueuePath(APath);
60 | try
61 | RegisterInternal(AHTTPType, LPathChain, ACallback);
62 | finally
63 | LPathChain.Free;
64 | end;
65 | end;
66 |
67 | function THorseRouterTree.CallNextPath(var APath: TQueue; const AHTTPType: TMethodType; const ARequest: THorseRequest;
68 | const AResponse: THorseResponse): Boolean;
69 | var
70 | LCurrent, LKey: string;
71 | LAcceptable: THorseRouterTree;
72 | LFound, LIsGroup: Boolean;
73 | LPathOrigin: TQueue;
74 | begin
75 | LIsGroup := False;
76 | LPathOrigin := APath;
77 | LCurrent := APath.Peek;
78 | LFound := FRoute.TryGetValue(LCurrent, LAcceptable);
79 | if (not LFound) then
80 | begin
81 | LFound := FRoute.TryGetValue(EmptyStr, LAcceptable);
82 | if (LFound) then
83 | APath := LPathOrigin;
84 | LIsGroup := LFound;
85 | end;
86 | if (not LFound) and (FRegexedKeys.Count > 0) then
87 | begin
88 | for LKey in FRegexedKeys do
89 | begin
90 | FRoute.TryGetValue(LKey, LAcceptable);
91 | if LAcceptable.HasNext(AHTTPType, APath.ToArray) then
92 | begin
93 | LFound := LAcceptable.ExecuteInternal(APath, AHTTPType, ARequest, AResponse);
94 | Break;
95 | end;
96 | end;
97 | end
98 | else if LFound then
99 | LFound := LAcceptable.ExecuteInternal(APath, AHTTPType, ARequest, AResponse, LIsGroup);
100 | Result := LFound;
101 | end;
102 |
103 | constructor THorseRouterTree.Create;
104 | begin
105 | FMiddleware := TList.Create;
106 | FRoute := TObjectDictionary.Create([doOwnsValues]);
107 | FRegexedKeys := TList.Create;
108 | FCallBack := TObjectDictionary < TMethodType, TList < THorseCallback >>.Create([doOwnsValues]);
109 | FPrefix := '';
110 | end;
111 |
112 | destructor THorseRouterTree.Destroy;
113 | begin
114 | FMiddleware.Free;
115 | FreeAndNil(FRoute);
116 | FRegexedKeys.Clear;
117 | FRegexedKeys.Free;
118 | FCallBack.Free;
119 | inherited;
120 | end;
121 |
122 | function THorseRouterTree.Execute(const ARequest: THorseRequest; const AResponse: THorseResponse): Boolean;
123 | var
124 | LQueue: TQueue;
125 | begin
126 | LQueue := GetQueuePath({$IF DEFINED(FPC)}ARequest.RawWebRequest.PathInfo{$ELSE}ARequest.RawWebRequest.RawPathInfo{$ENDIF}, False);
127 | try
128 | Result := ExecuteInternal(LQueue, {$IF DEFINED(FPC)} StringCommandToMethodType(ARequest.RawWebRequest.Method)
129 | {$ELSE} ARequest.RawWebRequest.MethodType{$ENDIF}, ARequest, AResponse);
130 | finally
131 | LQueue.Free;
132 | end;
133 | end;
134 |
135 | function THorseRouterTree.ExecuteInternal(const APath: TQueue; const AHTTPType: TMethodType; const ARequest: THorseRequest;
136 | const AResponse: THorseResponse; const AIsGroup: Boolean = False): Boolean;
137 | var
138 | LNextCaller: TNextCaller;
139 | LFound: Boolean;
140 | begin
141 | LFound := False;
142 | LNextCaller := TNextCaller.Create;
143 | try
144 | LNextCaller.SetCallback(FCallBack);
145 | LNextCaller.SetPath(APath);
146 | LNextCaller.SetHTTPType(AHTTPType);
147 | LNextCaller.SetRequest(ARequest);
148 | LNextCaller.SetResponse(AResponse);
149 | LNextCaller.SetIsGroup(AIsGroup);
150 | LNextCaller.SetMiddleware(FMiddleware);
151 | LNextCaller.SetTag(FTag);
152 | LNextCaller.SetIsRegex(FIsRegex);
153 | LNextCaller.SetOnCallNextPath(CallNextPath);
154 | LNextCaller.SetFound(LFound);
155 | LNextCaller.Init;
156 | LNextCaller.Next;
157 | finally
158 | LNextCaller.Free;
159 | Result := LFound;
160 | end;
161 | end;
162 |
163 | function THorseRouterTree.ForcePath(const APath: string): THorseRouterTree;
164 | begin
165 | if not FRoute.TryGetValue(APath, Result) then
166 | begin
167 | Result := THorseRouterTree.Create;
168 | FRoute.Add(APath, Result);
169 | end;
170 | end;
171 |
172 | function THorseRouterTree.CreateRouter(const APath: string): THorseRouterTree;
173 | begin
174 | Result := ForcePath(APath);
175 | end;
176 |
177 | procedure THorseRouterTree.Prefix(const APrefix: string);
178 | begin
179 | FPrefix := '/' + APrefix.Trim(['/']);
180 | end;
181 |
182 | function THorseRouterTree.GetPrefix: string;
183 | begin
184 | Result := FPrefix;
185 | end;
186 |
187 | function THorseRouterTree.GetQueuePath(APath: string; const AUsePrefix: Boolean = True): TQueue;
188 | var
189 | LPart: string;
190 | LSplitedPath: TArray;
191 | begin
192 | Result := TQueue.Create;
193 | if AUsePrefix then
194 | if not APath.StartsWith('/') then
195 | APath := (FPrefix + '/' + APath)
196 | else
197 | APath := (FPrefix + APath);
198 | LSplitedPath := APath.Split(['/']);
199 | for LPart in LSplitedPath do
200 | begin
201 | if (Result.Count > 0) and LPart.IsEmpty then
202 | Continue;
203 | Result.Enqueue(LPart);
204 | end;
205 | end;
206 |
207 | function THorseRouterTree.HasNext(const AMethod: TMethodType; const APaths: TArray; AIndex: Integer = 0): Boolean;
208 | var
209 | LNext, LKey: string;
210 | LNextRoute: THorseRouterTree;
211 | begin
212 | Result := False;
213 | if (Length(APaths) <= AIndex) then
214 | Exit(False);
215 | if (Length(APaths) - 1 = AIndex) and ((APaths[AIndex] = FPart) or (FIsRegex)) then
216 | Exit(FCallBack.ContainsKey(AMethod) or (AMethod = mtAny));
217 |
218 | LNext := APaths[AIndex + 1];
219 | Inc(AIndex);
220 | if FRoute.TryGetValue(LNext, LNextRoute) then
221 | begin
222 | Result := LNextRoute.HasNext(AMethod, APaths, AIndex);
223 | end
224 | else
225 | begin
226 | for LKey in FRegexedKeys do
227 | begin
228 | if FRoute.Items[LKey].HasNext(AMethod, APaths, AIndex) then
229 | Exit(True);
230 | end;
231 | end;
232 | end;
233 |
234 | procedure THorseRouterTree.RegisterInternal(const AHTTPType: TMethodType; var APath: TQueue; const ACallback: THorseCallback);
235 | var
236 | LNextPart: string;
237 | LCallbacks: TList;
238 | begin
239 | if not FIsInitialized then
240 | begin
241 | FPart := APath.Dequeue;
242 | FIsRegex := FPart.StartsWith(':');
243 | FTag := FPart.Substring(1, Length(FPart) - 1);
244 | FIsInitialized := True;
245 | end
246 | else
247 | APath.Dequeue;
248 |
249 | if APath.Count = 0 then
250 | begin
251 | if not FCallBack.TryGetValue(AHTTPType, LCallbacks) then
252 | begin
253 | LCallbacks := TList.Create;
254 | FCallBack.Add(AHTTPType, LCallbacks);
255 | end;
256 | LCallbacks.Add(ACallback)
257 | end;
258 |
259 | if APath.Count > 0 then
260 | begin
261 | LNextPart := APath.Peek;
262 | ForcePath(LNextPart).RegisterInternal(AHTTPType, APath, ACallback);
263 | if ForcePath(LNextPart).FIsRegex then
264 | FRegexedKeys.Add(LNextPart);
265 | end;
266 | end;
267 |
268 | procedure THorseRouterTree.RegisterMiddleware(const AMiddleware: THorseCallback);
269 | begin
270 | FMiddleware.Add(AMiddleware);
271 | end;
272 |
273 | procedure THorseRouterTree.RegisterMiddleware(const APath: string; const AMiddleware: THorseCallback);
274 | var
275 | LPathChain: TQueue;
276 | begin
277 | LPathChain := GetQueuePath(APath);
278 | try
279 | RegisterMiddlewareInternal(LPathChain, AMiddleware);
280 | finally
281 | LPathChain.Free;
282 | end;
283 | end;
284 |
285 | procedure THorseRouterTree.RegisterMiddlewareInternal(var APath: TQueue; const AMiddleware: THorseCallback);
286 | begin
287 | APath.Dequeue;
288 | if APath.Count = 0 then
289 | FMiddleware.Add(AMiddleware)
290 | else
291 | ForcePath(APath.Peek).RegisterMiddlewareInternal(APath, AMiddleware);
292 | end;
293 |
294 | end.
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Exception.Interrupted.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Exception.Interrupted;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils;
12 | {$ELSE}
13 | System.SysUtils;
14 | {$ENDIF}
15 |
16 | type
17 | EHorseCallbackInterrupted = class(Exception)
18 | constructor Create; reintroduce;
19 | end;
20 |
21 | implementation
22 |
23 | constructor EHorseCallbackInterrupted.Create;
24 | begin
25 | inherited Create(EmptyStr);
26 | end;
27 |
28 | end.
29 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Exception.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Exception;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils,
12 | {$ELSE}
13 | System.SysUtils,
14 | {$ENDIF}
15 | Horse.Commons;
16 |
17 | type
18 | EHorseException = class(Exception)
19 | strict private
20 | FError: string;
21 | FUnit: string;
22 | FTitle: string;
23 | FCode: Integer;
24 | FStatus: THTTPStatus;
25 | FType: TMessageType;
26 | constructor Create; reintroduce;
27 | public
28 | class function New: EHorseException;
29 | function Error(const AValue: string): EHorseException; overload;
30 | function Error: string; overload;
31 | function Title(const AValue: string): EHorseException; overload;
32 | function Title: string; overload;
33 | function &Unit(const AValue: string): EHorseException; overload;
34 | function &Unit: string; overload;
35 | function Code(const AValue: Integer): EHorseException; overload;
36 | function Code: Integer; overload;
37 | function Status(const AValue: THTTPStatus): EHorseException; overload;
38 | function Status: THTTPStatus; overload;
39 | function &Type(const AValue: TMessageType): EHorseException; overload;
40 | function &Type: TMessageType; overload;
41 | end;
42 |
43 | implementation
44 |
45 | function EHorseException.Code(const AValue: Integer): EHorseException;
46 | begin
47 | FCode := AValue;
48 | Result := Self;
49 | end;
50 |
51 | function EHorseException.&Type: TMessageType;
52 | begin
53 | Result := FType;
54 | end;
55 |
56 | function EHorseException.&Type(const AValue: TMessageType): EHorseException;
57 | begin
58 | FType := AValue;
59 | Result := Self;
60 | end;
61 |
62 | function EHorseException.Code: Integer;
63 | begin
64 | Result := FCode;
65 | end;
66 |
67 | function EHorseException.&Unit: string;
68 | begin
69 | Result := FUnit;
70 | end;
71 |
72 | function EHorseException.&Unit(const AValue: string): EHorseException;
73 | begin
74 | FUnit := AValue;
75 | Result := Self;
76 | end;
77 |
78 | constructor EHorseException.Create;
79 | begin
80 | FError := EmptyStr;
81 | FStatus := THTTPStatus.InternalServerError;
82 | FCode := 0;
83 | end;
84 |
85 | function EHorseException.Error: string;
86 | begin
87 | Result := FError;
88 | end;
89 |
90 | function EHorseException.Error(const AValue: string): EHorseException;
91 | begin
92 | FError := AValue;
93 | Result := Self;
94 | end;
95 |
96 | class function EHorseException.New: EHorseException;
97 | begin
98 | Result := EHorseException.Create;
99 | end;
100 |
101 | function EHorseException.Status: THTTPStatus;
102 | begin
103 | Result := FStatus;
104 | end;
105 |
106 | function EHorseException.Status(const AValue: THTTPStatus): EHorseException;
107 | begin
108 | FStatus := AValue;
109 | Result := Self;
110 | end;
111 |
112 | function EHorseException.Title(const AValue: string): EHorseException;
113 | begin
114 | FTitle := AValue;
115 | Result := Self;
116 | end;
117 |
118 | function EHorseException.Title: string;
119 | begin
120 | Result := FTitle;
121 | end;
122 |
123 | end.
124 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Proc.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Proc;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | {$IF NOT DEFINED(FPC)}
10 | uses System.SysUtils;
11 | {$ENDIF}
12 |
13 | type
14 | TNextProc = {$IF DEFINED(FPC)}procedure of object{$ELSE}System.SysUtils.TProc{$ENDIF};
15 | TProc = {$IF DEFINED(FPC)}procedure{$ELSE}System.SysUtils.TProc{$ENDIF};
16 |
17 | {$IF DEFINED(FPC)}
18 | TProc = procedure(Arg1: T);
19 | {$ENDIF}
20 |
21 | implementation
22 |
23 | end.
24 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Provider.Abstract.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Provider.Abstract;
2 |
3 | {$IF DEFINED(FPC)}
4 | {$MODE DELPHI}{$H+}
5 | {$ENDIF}
6 |
7 | interface
8 |
9 | uses
10 | {$IF DEFINED(FPC)}
11 | SysUtils, Horse.Proc,
12 | {$ELSE}
13 | System.SysUtils,
14 | {$ENDIF}
15 | Horse.Core;
16 |
17 | type
18 | THorseProviderAbstract = class(THorseCore)
19 | private
20 | class var FOnListen: TProc;
21 | class var FOnStopListen: TProc;
22 | class function GetOnStopListen: TProc; static;
23 | protected
24 | class function GetOnListen: TProc; static;
25 | class procedure SetOnListen(const AValue: TProc); static;
26 | class procedure SetOnStopListen(const AValue: TProc); static;
27 | class procedure DoOnListen;
28 | class procedure DoOnStopListen;
29 | public
30 | class property OnListen: TProc read GetOnListen write SetOnListen;
31 | class property OnStopListen: TProc read GetOnStopListen write SetOnStopListen;
32 | class procedure Listen; virtual; abstract;
33 | class procedure StopListen; virtual;
34 | end;
35 |
36 | implementation
37 |
38 | class procedure THorseProviderAbstract.DoOnListen;
39 | begin
40 | if Assigned(FOnListen) then
41 | FOnListen({$IF DEFINED(FPC)}T(GetInstance){$ELSE}GetInstance{$ENDIF});
42 | end;
43 |
44 | class procedure THorseProviderAbstract.DoOnStopListen;
45 | begin
46 | if Assigned(FOnStopListen) then
47 | FOnStopListen({$IF DEFINED(FPC)}T(GetInstance){$ELSE}GetInstance{$ENDIF});
48 | end;
49 |
50 | class function THorseProviderAbstract.GetOnListen: TProc;
51 | begin
52 | Result := FOnListen;
53 | end;
54 |
55 | class function THorseProviderAbstract.GetOnStopListen: TProc;
56 | begin
57 | Result := FOnStopListen;
58 | end;
59 |
60 | class procedure THorseProviderAbstract.SetOnListen(const AValue: TProc);
61 | begin
62 | FOnListen := AValue;
63 | end;
64 |
65 | class procedure THorseProviderAbstract.SetOnStopListen(const AValue: TProc);
66 | begin
67 | FOnStopListen := AValue;
68 | end;
69 |
70 | class procedure THorseProviderAbstract.StopListen;
71 | begin
72 | raise Exception.Create('StopListen not implemented');
73 | end;
74 |
75 | end.
76 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Provider.Apache.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Provider.Apache;
2 |
3 | interface
4 |
5 | {$IF DEFINED(HORSE_APACHE) AND NOT DEFINED(FPC)}
6 | uses Horse.Provider.Abstract, System.SysUtils, Web.HTTPD24Impl;
7 |
8 | type
9 | THorseProvider = class(THorseProviderAbstract)
10 | private
11 | class var FHandlerName: string;
12 | class var FDefaultModule: Pointer;
13 | class procedure InternalListen; static;
14 | class procedure SetHandlerName(const AValue: string); static;
15 | class function GetHandlerName: string; static;
16 | class function GetDefaultModule: Pointer; static;
17 | class procedure SetDefaultModule(const AValue: Pointer); static;
18 | public
19 | class property HandlerName: string read GetHandlerName write SetHandlerName;
20 | class property DefaultModule: Pointer read GetDefaultModule write SetDefaultModule;
21 | class procedure Listen; overload; override;
22 | class procedure Listen(const ACallback: TProc); reintroduce; overload; static;
23 | end;
24 | {$ENDIF}
25 |
26 | implementation
27 |
28 | {$IF DEFINED(HORSE_APACHE) AND NOT DEFINED(FPC)}
29 | uses
30 | Web.WebBroker, Web.ApacheApp,
31 | {$IFDEF MSWINDOWS}
32 | Winapi.ActiveX, System.Win.ComObj,
33 | {$ENDIF}
34 | Horse.WebModule;
35 |
36 | class procedure THorseProvider.InternalListen;
37 | begin
38 | {$IFDEF MSWINDOWS}
39 | CoInitFlags := COINIT_MULTITHREADED;
40 | {$ENDIF}
41 | Web.ApacheApp.InitApplication(FDefaultModule, UTF8String(FHandlerName));
42 | Application.Initialize;
43 | Application.WebModuleClass := WebModuleClass;
44 | DoOnListen;
45 | Application.Run;
46 | end;
47 |
48 | class procedure THorseProvider.Listen;
49 | begin
50 | inherited;
51 | InternalListen;
52 | end;
53 |
54 | class procedure THorseProvider.Listen(const ACallback: TProc);
55 | begin
56 | inherited;
57 | SetOnListen(ACallback);
58 | InternalListen;
59 | end;
60 |
61 | class function THorseProvider.GetHandlerName: string;
62 | begin
63 | Result := FHandlerName;
64 | end;
65 |
66 | class procedure THorseProvider.SetHandlerName(const AValue: string);
67 | begin
68 | FHandlerName := AValue;
69 | end;
70 |
71 | class function THorseProvider.GetDefaultModule: Pointer;
72 | begin
73 | Result := FDefaultModule;
74 | end;
75 |
76 | class procedure THorseProvider.SetDefaultModule(const AValue: Pointer);
77 | begin
78 | FDefaultModule := AValue;
79 | end;
80 | {$ENDIF}
81 |
82 | end.
83 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Provider.CGI.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Provider.CGI;
2 |
3 | interface
4 |
5 | {$IF DEFINED(HORSE_CGI) AND NOT DEFINED(FPC)}
6 | uses Horse.Provider.Abstract, System.SysUtils;
7 |
8 | type
9 | THorseProvider = class(THorseProviderAbstract)
10 | private
11 | class procedure InternalListen; static;
12 | public
13 | class procedure Listen; overload; override;
14 | class procedure Listen(const ACallback: TProc); reintroduce; overload; static;
15 | end;
16 | {$ENDIF}
17 |
18 | implementation
19 |
20 | {$IF DEFINED(HORSE_CGI) AND NOT DEFINED(FPC)}
21 | uses Web.WebBroker, Web.CGIApp, Horse.WebModule;
22 |
23 | class procedure THorseProvider.InternalListen;
24 | begin
25 | Application.Initialize;
26 | Application.WebModuleClass := WebModuleClass;
27 | DoOnListen;
28 | Application.Run;
29 | end;
30 |
31 | class procedure THorseProvider.Listen;
32 | begin
33 | inherited;
34 | InternalListen;
35 | end;
36 |
37 | class procedure THorseProvider.Listen(const ACallback: TProc);
38 | begin
39 | inherited;
40 | SetOnListen(ACallback);
41 | InternalListen;
42 | end;
43 | {$ENDIF}
44 |
45 | end.
46 |
--------------------------------------------------------------------------------
/Samples/Horse/Horse/src/Horse.Provider.Console.pas:
--------------------------------------------------------------------------------
1 | unit Horse.Provider.Console;
2 |
3 | interface
4 |
5 | {$IF NOT DEFINED(FPC)}
6 | uses Horse.Provider.Abstract, Horse.Constants, Horse.Provider.IOHandleSSL, IdHTTPWebBrokerBridge, IdSSLOpenSSL, IdContext,
7 | System.Classes, System.SyncObjs, System.SysUtils;
8 |
9 | type
10 | THorseProvider = class(THorseProviderAbstract)
11 | private
12 | class var FPort: Integer;
13 | class var FHost: string;
14 | class var FRunning: Boolean;
15 | class var FEvent: TEvent;
16 | class var FMaxConnections: Integer;
17 | class var FListenQueue: Integer;
18 | class var FIdHTTPWebBrokerBridge: TIdHTTPWebBrokerBridge;
19 | class var FHorseProviderIOHandleSSL: THorseProviderIOHandleSSL;
20 | class function GetDefaultHTTPWebBroker: TIdHTTPWebBrokerBridge;
21 | class function GetDefaultHorseProviderIOHandleSSL: THorseProviderIOHandleSSL;
22 | class function GetDefaultEvent: TEvent;
23 | class function HTTPWebBrokerIsNil: Boolean;
24 | class procedure OnAuthentication(AContext: TIdContext; const AAuthType, AAuthData: String; var VUsername, VPassword: String; var VHandled: Boolean);
25 | class procedure OnQuerySSLPort(APort: Word; var VUseSSL: Boolean);
26 | class procedure SetListenQueue(const AValue: Integer); static;
27 | class procedure SetMaxConnections(const AValue: Integer); static;
28 | class procedure SetPort(const AValue: Integer); static;
29 | class procedure SetIOHandleSSL(const AValue: THorseProviderIOHandleSSL); static;
30 | class procedure SetHost(const AValue: string); static;
31 | class function GetListenQueue: Integer; static;
32 | class function GetMaxConnections: Integer; static;
33 | class function GetPort: Integer; static;
34 | class function GetDefaultPort: Integer; static;
35 | class function GetDefaultHost: string; static;
36 | class function GetIOHandleSSL: THorseProviderIOHandleSSL; static;
37 | class function GetHost: string; static;
38 | class procedure InternalListen; virtual;
39 | class procedure InternalStopListen; virtual;
40 | class procedure InitServerIOHandlerSSLOpenSSL(const AIdHTTPWebBrokerBridge: TIdHTTPWebBrokerBridge; const AHorseProviderIOHandleSSL: THorseProviderIOHandleSSL);
41 | public
42 | class property Host: string read GetHost write SetHost;
43 | class property Port: Integer read GetPort write SetPort;
44 | class property MaxConnections: Integer read GetMaxConnections write SetMaxConnections;
45 | class property ListenQueue: Integer read GetListenQueue write SetListenQueue;
46 | class property IOHandleSSL: THorseProviderIOHandleSSL read GetIOHandleSSL write SetIOHandleSSL;
47 | class procedure StopListen; override;
48 | class procedure Listen; overload; override;
49 | class procedure Listen(const APort: Integer; const AHost: string = '0.0.0.0'; const ACallbackListen: TProc = nil; const ACallbackStopListen: TProc = nil); reintroduce; overload; static;
50 | class procedure Listen(const APort: Integer; const ACallbackListen: TProc; const ACallbackStopListen: TProc