brookframework
首先必须了解一下Sagui 是一个跨平台的 C 库,有助于开发 Web 服务器或框架。它的核心是使用 GNU libmicrohttpd、uthash、PCRE2、ZLib 和 GnuTLS 开发的,这就是它在嵌入式系统上运行如此快速、紧凑和有用的原因。
Sagui 编译好的库下载:https://github.com/risoflora/libsagui/releases
提供有FOR WINDOWS和FOR LINUX的库下载。
Sagui特性:
- Requests processing through:
- Event-driven - single-thread + polling.
- Threaded - one thread per request.
- Polling - pre-allocated threads.
- Isolated request - request processed outside main thread.
- High-performance path routing that supports:
- HTTP compression:
- HTTPS support:
- TLS 1.3 through GnuTLS library.
- Dual stack:
- Single socket for IPv4 and IPv6 support.
- Basic authentication:
- For standard login using user name/password.
- Upload/download streaming by:
- Payload - for raw data transferring as JSON, XML and other.
- File - for large data transferring as videos, images, binaries and so on.
- Mathematical expression evaluator:
- Arithmetic, bitwise and logical operators.
- Variables allocation at build and/or run time.
- Macro support to define functions at run time.
- Extendable with custom functions.
- Error handling with error kind and position.
- Dynamic strings:
- Makes it easy strings operations in C.
- String map:
- Fast key-value mapping.
- And more:
- Fields, parameters, cookies, headers under hash table structure.
- Several callbacks for total library customization.
BrookFramework 是一个跨平台的微框架,支持 Delphi 或 Lazarus 构建跨平台的开发框架。它的核心是使用 Sagui 库开发的,这就是它在嵌入式系统上运行如此快速、紧凑和有用的原因。
BrookFramework开源地址:https://github.com/risoflora/brookframework
Successfully tested on:
- Windows
- Linux
- Raspbian/Android
compiled using:
- Delphi XE family (Rio)
- Lazarus / Free Pascal (Lazarus 2.0+ / FPC 3.2+)
服务端:
uses BrookHTTPRequest, BrookHTTPResponse, BrookHTTPServer, Persistence; type THTTPServer = class(TBrookHTTPServer) protected procedure DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse); override; end; procedure THTTPServer.DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse); begin if ARequest.Payload.Length > 0 then SavePersons(ARequest.Payload.Content) else AResponse.SendStream(ListPersons, 200); end; begin with THTTPServer.Create(nil) do try Port := 8080; Open; if not Active then Exit; WriteLn('Server running at http://localhost:', Port); ReadLn; finally Free; end;
(* _ _ * | |__ _ __ ___ ___ | | __ * | '_ \| '__/ _ \ / _ \| |/ / * | |_) | | | (_) | (_) | < * |_.__/|_| \___/ \___/|_|\_\ * * Microframework which helps to develop web Pascal applications. * * Copyright (c) 2012-2021 Silvio Clecio <silvioprog@gmail.com> * * Brook framework is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Brook framework is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Brook framework; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) unit Persistence; interface uses System.SysUtils, System.Classes, FireDAC.DApt, FireDAC.Stan.Def, FireDAC.Stan.Intf, FireDAC.Stan.Async, FireDAC.Phys.SQLite, FireDAC.Comp.Client, FireDAC.Stan.StorageBin; function ListPersons: TStream; procedure SavePersons(const ABytes: TBytes); implementation const SQL_SELECT_PERSONS = 'SELECT * FROM persons'; SQL_INSERT_PERSONS = 'INSERT INTO persons (name) VALUES (:name)'; var DBConnection: TFDConnection; procedure CreateAndConfigureDBConnection; begin DBConnection := TFDConnection.Create(nil); DBConnection.DriverName := 'SQLite'; DBConnection.Params.Database := '../../../DB/DataBase.sqlite3'; end; procedure DestroyDBConnection; begin FreeAndNil(DBConnection); end; function CreateQuery(const ASelectSQL: string; const AInsertSQL: string = ''): TFDQuery; var VUpdate: TFDUpdateSQL; begin Result := TFDQuery.Create(nil); if not AInsertSQL.IsEmpty then begin VUpdate := TFDUpdateSQL.Create(Result); VUpdate.Connection := DBConnection; VUpdate.InsertSQL.Text := AInsertSQL; Result.UpdateObject := VUpdate; end; Result.Connection := DBConnection; Result.CachedUpdates := True; Result.SQL.Text := ASelectSQL; end; function ListPersons: TStream; var VQuery: TFDQuery; begin Result := TBytesStream.Create; VQuery := CreateQuery(SQL_SELECT_PERSONS); try VQuery.Open; VQuery.SaveToStream(Result, sfBinary); Result.Seek(0, TSeekOrigin.soBeginning); finally VQuery.Destroy; end; end; procedure SavePersons(const ABytes: TBytes); var VQuery: TFDQuery; VData: TBytesStream; begin VQuery := CreateQuery(SQL_SELECT_PERSONS, SQL_INSERT_PERSONS); VData := TBytesStream.Create(ABytes); try VQuery.LoadFromStream(VData, sfBinary); VQuery.ApplyUpdates; DBConnection.Commit; finally VQuery.Destroy; VData.Free; end; end; initialization CreateAndConfigureDBConnection; finalization DestroyDBConnection; end.
客户端:
(* _ _ * | |__ _ __ ___ ___ | | __ * | '_ \| '__/ _ \ / _ \| |/ / * | |_) | | | (_) | (_) | < * |_.__/|_| \___/ \___/|_|\_\ * * Microframework which helps to develop web Pascal applications. * * Copyright (c) 2012-2021 Silvio Clecio <silvioprog@gmail.com> * * Brook framework is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Brook framework is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Brook framework; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) unit Client; interface uses System.SysUtils, System.Classes, Data.DB, System.Net.HTTPClient, FireDAC.Stan.Intf, FireDAC.Comp.Client, FireDAC.Stan.StorageBin; function NewGuid: string; function ListPersons(const AURL: string): TDataSet; procedure SavePersons(const AURL: string; ADataSet: TDataSet); function CreatePersonsDataSet: TDataSet; implementation function NewGuid: string; begin Result := TGuid.NewGuid.ToString; end; function CreateDataSet: TFDMemTable; begin Result := TFDMemTable.Create(nil); Result.CachedUpdates := True; end; function ListPersons(const AURL: string): TDataSet; var VClient: THTTPClient; begin Result := CreateDataSet; VClient := THTTPClient.Create; try TFDMemTable(Result).LoadFromStream(VClient.Get(AURL).ContentStream, sfBinary); finally VClient.Free; end; end; procedure SavePersons(const AURL: string; ADataSet: TDataSet); var VClient: THTTPClient; VData: TStream; begin if ADataSet.State in dsEditModes then ADataSet.Post; try VData := TBytesStream.Create; VClient := THTTPClient.Create; try TFDMemTable(ADataSet).SaveToStream(VData, sfBinary); VData.Seek(0, TSeekOrigin.soBeginning); VClient.Post(AURL, VData); finally VClient.Free; VData.Free; end; finally FreeAndNil(ADataSet); end; end; function CreatePersonsDataSet: TDataSet; begin Result := CreateDataSet; Result.FieldDefs.Add('name', ftString, 100); TFDMemTable(Result).CreateDataSet; end; end.