TDiocpHttpServer
DIOCP只支持windows。
unit sock.DiocpHttpServer;
/// <author>cxg 2023-2-12</author>
interface
uses classes,
system.JSON, json.help, keyValue.serialize, api.router,
IniFiles, global, diocp_ex_httpServer, SysUtils;
var
BinApis: TJSONObject; //二进制API
RestApis: TJSONObject; //REST API,包括json,protobuf
const //content-type
cBin = 'application/octet-stream; charset=utf-8';
cJson = 'application/json; charset=utf-8';
cProtobuf = 'application/protobuf; charset=utf-8';
type
TiocpHttpServer = class
private
FServer: TDiocpHttpServer;
procedure OnHttpSvrRequest(pvRequest: TDiocpHttpRequest);
public
constructor Create; overload;
destructor Destroy; override;
end;
implementation
function ReadJsonFile(const FileName: string): string;
begin
var f: TStringList := TStringList.Create;
f.LoadFromFile(FileName, TEncoding.UTF8);
Result := f.Text;
f.Free;
end;
procedure setHeader(const Ctxt: TDiocpHttpRequest; const ContentType: string);
begin
Ctxt.Response.ContentType := ContentType;
Ctxt.Response.Header.ForceByName('Access-Control-Allow-Origin').AsString := '*';
Ctxt.Response.Header.ForceByName('Access-Control-Allow-Methods').AsString := '*';
Ctxt.Response.Header.ForceByName('Access-Control-Allow-Headers').AsString := '*';
end;
procedure router(const Ctxt: TDiocpHttpRequest); //diocp router
begin
if Pos('/bin', Ctxt.RequestURL) > 0 then //二进制 API
begin
setHeader(Ctxt, cBin);
var req: TSerialize := tserialize.Create;
var res: TSerialize := tserialize.Create;
if Ctxt.ContentBody.Length > 0 then
req.unMarshal(Ctxt.ContentBody.ToBytes);
var url: string := Ctxt.RequestURL;
var arr: TArray<string> := url.Split(['/']);
var funcName: string := arr[2];
var ja: TJSONArray := BinApis.A['bin'];
for var i: Integer := 0 to ja.Count - 1 do
begin
var o: TJSONObject := ja.Items[i] as TJSONObject;
if o.S['funcname'] = funcName then
begin
RouterAPI(o.S['classname'], o.S['funcname'], [req, res]);
Break;
end;
end;
var bs: TBytes := res.marshal2;
Ctxt.Response.WriteBuf(PByte(bs), Length(bs));
Ctxt.SendResponse();
req.Free;
res.Free;
end
else if Pos('/rest', Ctxt.RequestURL) > 0 then //JSON API
begin
setHeader(Ctxt, cJson);
var url: string := Ctxt.RequestURL;
var arr: TArray<string> := url.Split(['/']);
var resource: string := arr[2];
var req: TSerialize := tserialize.Create;
var res: TSerialize := tserialize.Create;
req.asStr['url'] := url;
if Ctxt.ContentBody.Length > 0 then
req.asStr['body'] := Ctxt.ContentBody.ToString;
req.asStr['type'] := 'json';
var ja: TJSONArray := RestApis.A[resource];
for var i: Integer := 0 to ja.Count - 1 do
begin
var o: TJSONObject := ja.Items[i] as TJSONObject;
if o.S['method'] = Ctxt.RequestMethod then
begin
RouterAPI(o.S['classname'], o.S['funcname'], [req, res]);
Break;
end;
end;
Ctxt.Response.WriteString(UTF8Encode(res.asStr['res']));
Ctxt.SendResponse();
req.Free;
res.Free;
end
else if Pos('/protobuf', Ctxt.RequestURL) > 0 then //PROTOBUF API
begin
setHeader(Ctxt, cProtobuf);
var url: string := Ctxt.RequestURL;
var arr: TArray<string> := url.Split(['/']);
var resource: string := arr[2];
var req: TSerialize := tserialize.Create;
var res: TSerialize := tserialize.Create;
req.asStr['url'] := url;
if Ctxt.ContentBody.Length > 0 then
req.asBytes['body'] := Ctxt.ContentBody.ToBytes;
req.asStr['type'] := 'protobuf';
var ja: TJSONArray := RestApis.A[resource];
for var i: Integer := 0 to ja.Count - 1 do
begin
var o: TJSONObject := ja.Items[i] as TJSONObject;
if o.S['method'] = Ctxt.RequestMethod then
begin
RouterAPI(o.S['classname'], o.S['funcname'], [req, res]);
Break;
end;
end;
var bs: TBytes := res.asBytes['res'];
Ctxt.Response.WriteBuf(PByte(bs), Length(bs));
Ctxt.SendResponse();
req.Free;
res.Free;
end;
end;
constructor TiocpHttpServer.Create;
var
ini: tinifile;
begin
FServer := TDiocpHttpServer.Create(nil);
FServer.UseObjectPool := True;
FServer.SetMaxSendingQueueSize(100000);
FServer.OnDiocpHttpRequest := OnHttpSvrRequest;
ini := TIniFile.Create(SvrCfg);
var threadnum: Integer := ini.readinteger('config', 'threadnum', 32);
if threadnum > 256 then
threadnum := 256;
FServer.WorkerCount := threadnum;
FServer.Port := ini.ReadInteger('config', 'httpport', 1234);
ini.free;
fserver.Active := True;
{$IFDEF console}
Writeln('New IOCP http server');
Writeln('Thread num: ', FServer.WorkerCount);
Writeln('Http port: ', FServer.Port);
{$ENDIF}
end;
destructor TiocpHttpServer.Destroy;
begin
FServer.DisConnectAll();
FServer.SafeStop;
FServer.Free;
inherited;
end;
procedure TiocpHttpServer.OnHttpSvrRequest(pvRequest: TDiocpHttpRequest);
begin
router(pvRequest);
end;
initialization
binapis := TJSONObject.Create;
restapis := TJSONObject.Create;
binapis.Parse(ReadJsonFile(ExtractFilePath(ParamStr(0)) + 'binrouter.json'));
restapis.Parse(ReadJsonFile(ExtractFilePath(ParamStr(0)) + 'restrouter.json'));
finalization
FreeAndNil(binapis);
FreeAndNil(restapis);
end.