delphimvcframework/sources/MVCFramework.SysControllers.pas

296 lines
9.7 KiB
ObjectPascal
Raw Normal View History

// ***************************************************************************
//
// Delphi MVC Framework
//
2024-01-02 17:04:27 +01:00
// Copyright (c) 2010-2024 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// *************************************************************************** }
2015-12-22 12:38:17 +01:00
2015-04-01 17:01:23 +02:00
unit MVCFramework.SysControllers;
{$I dmvcframework.inc}
interface
2015-04-01 17:01:23 +02:00
uses
System.SysUtils,
System.Classes,
System.TypInfo,
System.DateUtils,
System.Rtti,
MVCFramework,
2019-10-09 23:14:56 +02:00
MVCFramework.Commons, MVCFramework.Swagger.Commons;
2015-04-01 17:01:23 +02:00
2022-01-04 15:44:47 +01:00
const
DESCRIBE_PLATFORM_RESPONSE_SWAGGER_SCHEMA =
'{' + sLineBreak +
' "type": "object",' + sLineBreak +
' "properties": {' + sLineBreak +
' "OS": {' + sLineBreak +
' "type": "string",' + sLineBreak +
' "description": "Operating System Information"' + sLineBreak +
' },' + sLineBreak +
' "CPU_count": {' + sLineBreak +
' "type": "integer",' + sLineBreak +
' "description": "Numbers of cores available "' + sLineBreak +
' },' + sLineBreak +
' "CPU_architecture": {' + sLineBreak +
' "type": "string",' + sLineBreak +
' "description": "CPU''s Architecture"' + sLineBreak +
' },' + sLineBreak +
' "system_time": {' + sLineBreak +
' "type": "string",' + sLineBreak +
' "description": "Server timestamp"' + sLineBreak +
' }' + sLineBreak +
' }' + sLineBreak +
'}';
2015-04-01 17:01:23 +02:00
type
[MVCPath('/system')]
[MVCDoc('Built-in DelphiMVCFramework System Controller')]
2015-04-01 17:01:23 +02:00
TMVCSystemController = class(TMVCController)
private
{ private declarations }
2015-04-01 17:01:23 +02:00
protected
procedure OnBeforeAction(AContext: TWebContext; const AActionName: string; var AHandled: Boolean); override;
2015-04-01 17:01:23 +02:00
function GetUpTime: string;
public
[MVCPath('/describeserver.info')]
2019-10-09 23:14:56 +02:00
[MVCHTTPMethods([httpGET])]
[MVCDoc('Describe controllers and actions published by the RESTful server per resources')]
2019-10-09 23:14:56 +02:00
[MVCSwagSummary('DMVCFramework System Controller', 'Describe controllers and actions published by the RESTful server per resources')]
2022-01-04 15:44:47 +01:00
[MVCSwagResponses(HTTP_STATUS.InternalServerError, 'Internal server error', TMVCErrorResponse)]
[MVCSwagResponses(HTTP_STATUS.OK, 'OK')]
2019-05-02 17:38:57 +02:00
procedure DescribeServer;
2015-04-01 17:01:23 +02:00
[MVCPath('/describeplatform.info')]
[MVCDoc('Describe the system where server is running')]
2019-10-09 23:14:56 +02:00
[MVCHTTPMethods([httpGET])]
[MVCSwagSummary('DMVCFramework System Controller', 'Describe the system where server is running')]
2022-01-04 15:44:47 +01:00
[MVCSwagResponses(HTTP_STATUS.InternalServerError, 'Internal server error', TMVCErrorResponse)]
[MVCSwagResponses(HTTP_STATUS.OK, 'OK', DESCRIBE_PLATFORM_RESPONSE_SWAGGER_SCHEMA)]
2019-05-02 17:38:57 +02:00
procedure DescribePlatform;
2015-04-01 17:01:23 +02:00
[MVCPath('/serverconfig.info')]
2019-10-09 23:14:56 +02:00
[MVCHTTPMethods([httpGET])]
[MVCDoc('Server configuration')]
2019-10-09 23:14:56 +02:00
[MVCSwagSummary('DMVCFramework System Controller', 'Server configuration')]
2022-01-04 15:44:47 +01:00
[MVCSwagResponses(HTTP_STATUS.InternalServerError, 'Internal server error', TMVCErrorResponse)]
[MVCSwagResponses(HTTP_STATUS.OK, 'OK')]
2019-05-02 17:38:57 +02:00
procedure ServerConfig;
2015-04-01 17:01:23 +02:00
end;
implementation
uses
JsonDataObjects, MVCFramework.ActiveRecord;
2015-04-01 17:01:23 +02:00
function MSecToTime(mSec: Int64): string;
const
secondTicks = 1000;
minuteTicks = 1000 * 60;
hourTicks = 1000 * 60 * 60;
dayTicks = 1000 * 60 * 60 * 24;
var
D, H, M, S: string;
ZD, ZH, ZM, ZS: Integer;
begin
ZD := mSec div dayTicks;
Dec(mSec, ZD * dayTicks);
ZH := mSec div hourTicks;
Dec(mSec, ZH * hourTicks);
ZM := mSec div minuteTicks;
Dec(mSec, ZM * minuteTicks);
ZS := mSec div secondTicks;
D := IntToStr(ZD);
H := IntToStr(ZH);
M := IntToStr(ZM);
S := IntToStr(ZS);
Result := D + '.' + H + ':' + M + ':' + S;
end;
{ TMVCSystemController }
2019-05-02 17:38:57 +02:00
procedure TMVCSystemController.DescribePlatform;
2015-04-01 17:01:23 +02:00
var
Jo: TJSONObject;
2015-04-01 17:01:23 +02:00
begin
Jo := TJSONObject.Create;
2015-04-01 17:01:23 +02:00
try
Jo.S['OS'] := TOSVersion.ToString;
Jo.I['CPU_count'] := TThread.ProcessorCount;
Jo.S['CPU_architecture'] := GetEnumName(TypeInfo(TOSVersion.TArchitecture), Ord(TOSVersion.Architecture));
Jo.DUtc['system_time'] := Now;
ContentType := TMVCMediaType.APPLICATION_JSON;
Render(Jo, False);
2015-04-01 17:01:23 +02:00
finally
Jo.Free;
2015-04-01 17:01:23 +02:00
end;
end;
2019-05-02 17:38:57 +02:00
procedure TMVCSystemController.DescribeServer;
2015-04-01 17:01:23 +02:00
var
LJoResp: TJSONObject;
LController: TMVCControllerDelegate;
LRttiType: TRttiInstanceType;
LRttiCtx: TRttiContext;
2015-04-01 17:01:23 +02:00
LAttribute: TCustomattribute;
LJaMethods: TJSONArray;
2015-04-01 17:01:23 +02:00
LMethods: TArray<TRttiMethod>;
LMethod: TRttiMethod;
LFoundAttrib: Boolean;
LStrRelativePath: string;
LStrHTTPMethods: string;
LStrDoc: string;
2015-04-01 17:01:23 +02:00
LStrConsumes: string;
LStrProduces: string;
LJoMethod: TJSONObject;
lControllerClassName: string;
2015-04-01 17:01:23 +02:00
begin
LRttiCtx := TRttiContext.Create;
2015-04-01 17:01:23 +02:00
try
LJoResp := TJSONObject.Create;
try
for LController in Engine.Controllers do
2015-04-01 17:01:23 +02:00
begin
lControllerClassName := LController.Clazz.QualifiedClassName;
if lControllerClassName.EndsWith('TMVCActiveRecordController') then
begin
LJoResp.O[lControllerClassName].S['description'] := 'Automatic CRUD API for entities: ' +
String.Join(',', ActiveRecordMappingRegistry.GetEntities);
end;
LRttiType := LRttiCtx.GetType(LController.Clazz) as TRttiInstanceType;
for LAttribute in LRttiType.GetAttributes do
2015-04-01 17:01:23 +02:00
begin
if LAttribute is MVCPathAttribute then
LJoResp.O[lControllerClassName].S['resource_path'] := MVCPathAttribute(LAttribute).Path;
if LAttribute is MVCDocAttribute then
LJoResp.O[lControllerClassName].S['description'] := MVCDocAttribute(LAttribute).Value;
end;
if not LController.URLSegment.IsEmpty then
begin
LJoResp.O[lControllerClassName].S['resource_path'] := LController.URLSegment;
end;
LJaMethods := LJoResp.O[lControllerClassName].A['actions']; // TJSONArray.Create;
// LJoControllerInfo.AddPair('actions', LJaMethods);
LMethods := LRttiType.GetMethods;
for LMethod in LMethods do
begin
LFoundAttrib := False;
LStrRelativePath := '';
LStrHTTPMethods := '';
LStrConsumes := '';
LStrProduces := '';
LStrDoc := '';
LStrHTTPMethods := 'httpGET,httpPOST,httpPUT,httpDELETE,httpHEAD,httpOPTIONS,httpPATCH,httpTRACE';
for LAttribute in LMethod.GetAttributes do
2015-04-01 17:01:23 +02:00
begin
if LAttribute is MVCDocAttribute then
begin
LStrDoc := MVCDocAttribute(LAttribute).Value;
LFoundAttrib := true;
end;
if LAttribute is MVCPathAttribute then
begin
LStrRelativePath := MVCPathAttribute(LAttribute).Path;
LFoundAttrib := true;
end;
if LAttribute is MVCHTTPMethodAttribute then
begin
LStrHTTPMethods := MVCHTTPMethodAttribute(LAttribute).MVCHTTPMethodsAsString;
LFoundAttrib := true;
end;
if LAttribute is MVCConsumesAttribute then
begin
LStrConsumes := MVCConsumesAttribute(LAttribute).Value;
LFoundAttrib := true;
end;
if LAttribute is MVCProducesAttribute then
begin
LStrProduces := MVCProducesAttribute(LAttribute).Value;
LFoundAttrib := true;
end;
2015-04-01 17:01:23 +02:00
end;
if LFoundAttrib then
2015-04-01 17:01:23 +02:00
begin
LJoMethod := LJaMethods.AddObject;
LJoMethod.S['action_name'] := LMethod.Name;
LJoMethod.S['relative_path'] := LStrRelativePath;
LJoMethod.S['consumes'] := LStrConsumes;
LJoMethod.S['produces'] := LStrProduces;
LJoMethod.S['http_methods'] := LStrHTTPMethods;
LJoMethod.S['description'] := LStrDoc;
2015-04-01 17:01:23 +02:00
end;
end;
end;
ContentType := TMVCMediaType.APPLICATION_JSON;
Render(LJoResp, False);
finally
LJoResp.Free;
2015-04-01 17:01:23 +02:00
end;
finally
LRttiCtx.Free;
2015-04-01 17:01:23 +02:00
end;
end;
function TMVCSystemController.GetUpTime: string;
begin
Result := MSecToTime(MilliSecondsBetween(Now, 0));
2015-04-01 17:01:23 +02:00
end;
procedure TMVCSystemController.OnBeforeAction(AContext: TWebContext; const AActionName: string; var AHandled: Boolean);
2015-05-18 12:16:34 +02:00
var
ClientIp: string;
2015-04-01 17:01:23 +02:00
begin
inherited;
ClientIp := Context.Request.ClientIp;
AHandled := not((ClientIp = '::1') or (ClientIp = '127.0.0.1') or (ClientIp = '0:0:0:0:0:0:0:1') or
(ClientIp.ToLower = 'localhost'));
2019-05-02 17:38:57 +02:00
if AHandled then
begin
AContext.Response.StatusCode := HTTP_STATUS.Forbidden;
end;
2015-04-01 17:01:23 +02:00
end;
2019-05-02 17:38:57 +02:00
procedure TMVCSystemController.ServerConfig;
2015-04-01 17:01:23 +02:00
var
Keys: TArray<string>;
Key: string;
Jo: TJSONObject;
2015-04-01 17:01:23 +02:00
begin
Jo := TJSONObject.Create;
2015-04-01 17:01:23 +02:00
try
Keys := Config.Keys;
for Key in Keys do
Jo.S[Key] := Config[Key];
ContentType := TMVCMediaType.APPLICATION_JSON;
Render(Jo, False);
2017-02-10 14:19:55 +01:00
finally
Jo.Free;
2015-04-01 17:01:23 +02:00
end;
end;
end.