You are not logged in.
Hi @ab,
I need to use streaming feature of the framework and I found problems when the file fire more of one request with the header "Range". In this link https://drive.google.com/file/d/1kO3dh2 … sp=sharing it's a demo with a server and a web page client that reproduce the problem.
In the subfolder "video" are the test video files with these problems:
video1.mp4: is OK with Firefox but not works with Chrome with error 416-Range Not Satisfiable
video2.mp4: fail with both Firefox and Chrome with error 416-Range Not Satisfiable
video3.mp4: is OK with Firefox but not works with Chrome with error 416-Range Not Satisfiable
video4.mp4: is OK with Firefox but not works with Chrome with error 416-Range Not Satisfiable
I have noticed that when the file size require more parts both the method service and the interface service are invoked more of once.
I tried solve this but was impossible for me and I really need this feature working. Time ago this was working I could play a movie.
Can you help me ?
Thanks in advance.
PD: the commit is 4088
Winhttp.dll have two constants definition in syncrtsock.pas: winhttpdll and winhttp_dll, I think that the problem Is there.
I think that it's related with new win HTTP API units of websockets from @mpv
Thank you @ab, works fine !!!
Do you not agree ?
Hi @ab,
I need more fields in inherited TSQLRecordHistory:
TSQLARISHistory = class(TSQLRecordHistory)
protected
fLogonName: RawUTF8;
fTableName: RawUTF8;
fRecID: TID;
published
property LogonName: RawUTF8 index 50 read fLogonName write fLogonName;
property RecID: TID read fRecID write fRecID;
property TableName: RawUTF8 index 50 read fTableName write fTableName;
end;and I have modified mORMot.pas in this way:
interface
...
type
...
TSQLRestServer = class(TSQLRest)
protected
...
function MainEngineUpdateFieldIncrement(TableModelIndex: integer; ID: TID;
const FieldName: RawUTF8; Increment: Int64): boolean; virtual; abstract;
/// Fields serialization for history tracking changes
// - Fields: name value pairs for JSON serialization.
// - JSON: JSON serialized fields
procedure DoHistoryFieldsSerialization(const Fields: array of const; var JSON: RawUTF8); virtual;
...
end;
implementation
...
procedure TSQLRestServer.DoHistoryFieldsSerialization(const Fields: array of const; var JSON: RawUTF8);
begin
JSON := JSONEncode(Fields);
end;
function TSQLRestServer.InternalUpdateEvent(aEvent: TSQLEvent; aTableIndex: integer;
aID: TID; const aSentData: RawUTF8; aIsBlobFields: PSQLFieldBits): boolean;
procedure DoTrackChanges;
var TableHistoryIndex: integer;
JSON: RawUTF8;
Event: TSQLHistoryEvent;
begin
case aEvent of
seAdd: Event := heAdd;
seUpdate: Event := heUpdate;
seDelete: Event := heDelete;
else exit;
end;
TableHistoryIndex := fTrackChangesHistoryTableIndex[aTableIndex];
fAcquireExecution[execORMWrite].Safe.Lock; // avoid race condition
try // low-level Add(TSQLRecordHistory) without cache
DoHistoryFieldsSerialization(['ModifiedRecord',aTableIndex+aID shl 6,'Event',ord(Event),
'SentDataJSON',aSentData,'TimeStamp',ServerTimeStamp], JSON); // <<--- call new procedure
fAcquireExecution[execORMWrite].fSafe.Lock;
try // may be within a batch in another thread
EngineAdd(TableHistoryIndex,JSON);
finally
fAcquireExecution[execORMWrite].fSafe.Unlock;
end;
{ TODO: use a BATCH (in background thread) to speed up TSQLHistory storage }
if fTrackChangesHistory[TableHistoryIndex].CurrentRow>
fTrackChangesHistory[TableHistoryIndex].MaxSentDataJsonRow then begin
// gather & compress TSQLRecordHistory.SentDataJson into History BLOB
TrackChangesFlush(TSQLRecordHistoryClass(Model.Tables[TableHistoryIndex]));
fTrackChangesHistory[TableHistoryIndex].CurrentRow := 0;
end else
// fast append as JSON until reached MaxSentDataJsonRow
inc(fTrackChangesHistory[TableHistoryIndex].CurrentRow);
finally
fAcquireExecution[execORMWrite].Safe.UnLock;
end;
end;
begin
...
end;and I implemented DoHistorySerialization in my code:
...
procedure TARISRestServer.DoHistoryFieldsSerialization(const Fields: array of const; var JSON: RawUTF8);
var
lFields: TDocVariantData;
begin
lFields.InitObject(Fields);
lFields.AddValue('LogonName',ServiceContext.Request.SessionUserName);
lFields.AddValue('RecID',lFields.Value['ModifiedRecord'] shr 6);
lFields.AddValue('TableName',fModel.Tables[lFields.I['ModifiedRecord'] and 63].SQLTableName);
JSON := lFields.ToJSON;
end;
...and all works OK !!!
Are you agree with this modification and can you apply them ?
Thanks in advance.
I don't think to have the enough knowledge base to implement this new feature, I'll think about this.
Thanks.
Hi @mpv, it is posible to use THTTPAPIWebSocketServer with TSQLRestServer in the same way that TSQLHTTPServer ?
Thanks.
In "Location: Title/23" it's the answer: "23" is the new ID in table "Title".
Check the headers in the HTTP response, the new record ID is there.
Great work @mpv !!!
Just for curiosity, why not just to use a function for readonly access in https://synopse.info/fossil/info/1ff1e5b5c276dcb5 ?
Solved busy error but still I need the fields, maybe de JSONEncode, in DoTrackChanges local procedure, can be moved as virtual function. What think you about this ?
Thanks.
I know, but for third party external processes accessing with JSON REST this values are not works.
@ab with TSQLRecordHistory the error still persists, how I must to configure the TSQLRestServerDB for ensure a single process open the associated SQLite3 database ? I have to define all "AcquireExecutionMode" to same value ? What would be those value ?
Sorry for many questions but I am confusing.
Thanks.
Thanks @ab, I see that TSQLRecordHistory can compliance my requirements but I would need that the record ID and the table name fields exists explicitly in the table, this is for external services that can read and delete the records. Can you add this fields ? I really would appreciate this feature.
Thanks.
Hi @ab,
I have the secBusy error (code = 5) when storing in a local SQLite3 table (no external mapping) the notified changes in OnUpdateEventLog and the system is under high load. The local table it is in the main REST server together to external tables. I need notify to an third party external process the changes on some tables. Is there another way ?
Any suggestion I will appreciate you.
TIA.
OpenUI5 is oriented to enterprise, the development is very active and the UI tends to UX, it have 600+ components, routing, internalization, etc, builtin the framework but is big and not very easy. I have an eye on Google Polymer https://www.polymer-project.org/ and other eye on Vaadin elements based on Polymer https://vaadin.com/elements.
Best regards.
I recommend you create a ticket.
Best regards.
Hi @ab, this is the sequence call between first call and next:
procedure TSQLRestServerURIContext.ExecuteORMGet;
...
// use the first static table (poorman's JOIN)
Static := Server.InternalAdaptSQL(TableIndexes[0],SQL); //--> always executed
end;
end;
if Static<>nil then begin
TableEngine := Static;
Call.OutBody := TableEngine.EngineList(SQL); //--> always executed after first time
end else
Call.OutBody := Server.MainEngineList(SQL,false,nil); //--> executed ONLY the firs time
// security note: only first statement is run by EngineList()
if Call.OutBody<>'' then begin // got JSON list '[{...}]' ?
...
end;
procedure TSQLRestServerDB.PrepareStatement(Cached: boolean);
var wasPrepared: boolean;
timer: PPPrecisionTimer;
begin
fStaticStatementTimer.Start;
if not Cached then begin
fStaticStatement.Prepare(DB.DB,fStatementGenericSQL); //--> executed the first time (called from PrepareStatement->GetAndPrepareStatement->MainEngineList)
fStatementGenericSQL := ''; // then this call to TSQLRequest.Prepare->mORMotSQLite3.vt_create->TSQLVirtualTable.Create
...
end;The first time the error is like this (varying the table and the field names):
20170615 12425630 ( EXC ESQLite3Exception {"ErrorCode":1,"SQLite3ErrorCode":"secERROR","Message":"Error SQLITE_ERROR (1) [SELECT ID,IDMDService,Code,Statement,CRC,LastAccess,MDServiceType,Description,BinData,Internal,Statement_U,Description_U FROM MDServices] using 3.19.2 - no such column: ID, extended_errcode=1"} at 006FED8A SynSQLite3.sqlite3_check (5319) stack trace API
The virtual table registration this table is:
VirtualTableExternalMap(fModel, TSQLMDServices, fConnPropSQLAdmin, 'TV_MDSERVICES').
MapFields(['ID','IDMDSERVICE']).
SetOptions([rpmAutoMapKeywordFields, rpmNoCreateMissingTable, rpmNoCreateMissingField]);
With the next calls all works fine.
My workaround is dirty and bad performance:
for I := Low(fModel.Tables) to High(fModel.Tables) do begin
if (fModel.Props[fModel.Tables[I]].Kind in [rCustomForcedID, rCustomAutoID]) then begin // only external tables
lMappingVersion := fModel.Props[fModel.Tables[I]].ExternalDB.MappingVersion;
if lMappingVersion>1 then // only with mapped fields
fServerRest.TableHasRows(fModel.Tables[I]);
end;
end;For me this a bug but you have the last word. ![]()
Thanks.
Yes of course. I have registered virtual external tables using SetOptions with NotCreateMissingFields (a database script make this), I can see the virtual external tables in the SQLite3 db. When the application start, the first time, the GET collection data request, the column ID is not sent, the next time yes. With non external tables I haven't this problem.
Thanks.
Hi @ab, I have a problem with ID field in an external virtual table in the first call, the GET request http://host:port/root/tablename?select=* the answer is with error "400 bad request", in the next call the response is ok, when debugging I detected that with the first call the mORMotSQLite3.vt_Create function is invoked and then mORMot.TSQLVirtualTable.Create and this register the table in aServer.fStaticVirtualTable, with this allow the correct response in next calls.
Thanks.
Yes, is an general error with mORMot and Delphi Dataset from a few weeks ago, is not only TSynRestDataset problem. In the next two week I will be able to see to solve it.
Any news ?
@ab, don't you agree with this modification ? I consider that it's an enhacement.
Best regards.
my solution solved my problem with new data but not with existing, I can confirm that the bug regression still exists.
Hi @ab, I have modified SynCrtSock.pas adding response management to error ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED (12044) when the server requests client authentication but not require it.
It's not a big modification:
const
// from http://www.tek-tips.com/faqs.cfm?fid=7493
WINHTTP_OPTION_SECURITY_FLAGS = 31;
SECURITY_FLAG_IGNORE_UNKNOWN_CA = $00000100;
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID = $00002000; // expired X509 Cert.
SECURITY_FLAG_IGNORE_CERT_CN_INVALID = $00001000; // bad common name in X509 Cert.
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE = $00000200;
SECURITY_FLAT_IGNORE_CERTIFICATES: DWORD =
SECURITY_FLAG_IGNORE_UNKNOWN_CA or
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID or
SECURITY_FLAG_IGNORE_CERT_CN_INVALID or
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
WINHTTP_AUTH_TARGET_SERVER = 0;
WINHTTP_AUTH_TARGET_PROXY = 1;
WINHTTP_AUTH_SCHEME_BASIC = $00000001;
WINHTTP_AUTH_SCHEME_NTLM = $00000002;
WINHTTP_AUTH_SCHEME_PASSPORT = $00000004;
WINHTTP_AUTH_SCHEME_DIGEST = $00000008;
WINHTTP_AUTH_SCHEME_NEGOTIATE = $00000010;
// client authentication certificate errors
ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED = $00002F0C; // 12044 code error returned by GetLastError()
WINHTTP_OPTION_CLIENT_CERT_CONTEXT = $0000002F;
WINHTTP_NO_CLIENT_CERT_CONTEXT = $00000000;
procedure TWinHTTP.InternalSendRequest(const aData: SockString);
var L: integer;
winAuth: DWORD;
begin
with fExtendedOptions do
if AuthScheme<>wraNone then begin
case AuthScheme of
wraBasic: winAuth := WINHTTP_AUTH_SCHEME_BASIC;
wraDigest: winAuth := WINHTTP_AUTH_SCHEME_DIGEST;
wraNegotiate: winAuth := WINHTTP_AUTH_SCHEME_NEGOTIATE;
else raise EWinHTTP.CreateFmt('Unsupported AuthScheme=%d',[ord(AuthScheme)]);
end;
if not WinHttpSetCredentials(fRequest,WINHTTP_AUTH_TARGET_SERVER,
winAuth,pointer(AuthUserName),pointer(AuthPassword),nil) then
RaiseLastModuleError(winhttpdll,EWinHTTP);
end;
if fHTTPS and IgnoreSSLCertificateErrors then begin
if not WinHttpSetOption(fRequest, WINHTTP_OPTION_SECURITY_FLAGS,
@SECURITY_FLAT_IGNORE_CERTIFICATES, SizeOf(SECURITY_FLAT_IGNORE_CERTIFICATES)) then
RaiseLastModuleError(winhttpdll,EWinHTTP);
end;
L := length(aData);
if not WinHttpSendRequest(fRequest, nil, 0, pointer(aData), L, L, 0) or
not WinHttpReceiveResponse(fRequest,nil) then begin
if not fHTTPS then
RaiseLastModuleError(winhttpdll,EWinHTTP);
if GetLastError=ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED then begin
if not WinHttpSetOption(fRequest, WINHTTP_OPTION_SECURITY_FLAGS,
@SECURITY_FLAT_IGNORE_CERTIFICATES, SizeOf(SECURITY_FLAT_IGNORE_CERTIFICATES)) then
RaiseLastModuleError(winhttpdll,EWinHTTP);
if not WinHttpSetOption(fRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
pointer(WINHTTP_NO_CLIENT_CERT_CONTEXT), 0) then
RaiseLastModuleError(winhttpdll,EWinHTTP);
if not WinHttpSendRequest(fRequest, nil, 0, pointer(aData), L, L, 0) or
not WinHttpReceiveResponse(fRequest,nil) then
RaiseLastModuleError(winhttpdll,EWinHTTP);
end;
end;
end;Do you agree with add this feature ?
Thanks.
Hi people, I need to use TWinHTTP with a https server (non mORMot) and I receive the error error 12044 a certificate is required, is TWinHTTP prepared to work with certificates ?
Thanks in advance.
Sorry for my bad expressions. I describe you the usage of this method with my code for showing the ambiguous description in the documentation (for me).
I have my class declaration:
...
TARISClient = class(TObject)
protected
...
fWebSocketClient: TSQLHttpClientWebsockets; // for websocket callbacks
fCallbackService: IARISCallbackService; // callback interface
fClient: TSQLRestClientURI; // mORMot client
fLastErrorMessage: RawUTF8;
...
public
...
CallbackClient: IARISCallbackClient;
constructor Create;
...
function CallbackCreate(const aHost, aPort: string; out aCallback: IARISCallbackClient): Boolean;
...
/// Cliente websocket
property WSClient: TSQLHttpClientWebsockets read fWebSocketClient;
...
end;class implementation:
constructor TARISClient.Create;
...
fClient := TSQLHttpClient.Create(...);
...
end;
...
function TARISClient.CallbackCreate(const aHost, aPort: string; out aCallback: IARISCallbackClient): Boolean;
begin
// se crea el websocket cliente
fWebSocketClient := TSQLHttpClientWebsockets.Create(...));
fWebSocketClient.Model.Owner := fWebSocketClient;
// se usa el websocket con protocolo binario
fWebSocketClient.WebSocketsUpgrade(ARIS_WS_TRANSMISSION_KEY);
if not fWebSocketClient.ServerTimeStampSynchronize then
begin
fLastErrorMessage := FormatUTF8(SErrorConnectingToTheServer, [lHost, lPort]) + ' / ' + fWebSocketClient.LastErrorMessage;;
Exit;
end;
// se cargan los servicios definidos para los websockets
fWebSocketClient.ServiceDefine([IARISCallbackService], sicShared);
if not fWebSocketClient.Services.Resolve(IARISCallbackService, fCallbackService) then
begin
fLastErrorMessage := SServiceIARISCallbackServiceUnava + ' / ' + fWebSocketClient.LastErrorMessage;;
Exit;
end;
// se crea el callback cliente que será invocado cuando se reciba una notificación websocket desde el servidor
aCallback := TARISCallbackClient.Create(fWebSocketClient, IARISCallbackClient);
// si está asignado el evento para cuando se recibe un callback se lo asigna al callback cliente creado para que
// luego propague la notificación
if Assigned(fOnCallback) then
TARISCallbackClient(ObjectFromInterface(aCallback)).OnCallback := fOnCallback; // allow it callback propagation when used in a TForm
Result := True;
end;
...then I use the client and the callbacks in visual application:
class declaration:
const
WM_SERVICENOTIFICATION = WM_USER+123;
type
...
TfrmARISClient = class(TForm)
protected
...
fARISClient: TARISClient;
fCallback: IARISCallbackClient;
...
procedure ServiceNotification(var Msg: TMessage); message WM_SERVICENOTIFICATION;
procedure DoOnCallback(const aJSONCallback: RawUTF8);
...
public
...
end;
...class implementation and usage:
...
procedure TfrmARISClient.FormCreate(Sender: TObject);
begin
...
// se crea el cliente de ARIS
fARISClient := TARISClient.Create(...);
if not fARISClient.Client.ServerTimeStampSynchronize then
raise Exception.Create('No se pudo conectar con ARIS');
...
// se suscribe al callback para recibir notificaciones
fARISClient.CallbackCreate(...,...,fCallback);
// evento que procesa los callbacks
TARISCallbackClient(ObjectFromInterface(fCallback)).OnCallback := DoOnCallback;
// procesar callbacks en la hebra principal
fARISClient.WSClient.ServiceNotificationMethodViaMessages(Handle,WM_SERVICENOTIFICATION); //--> *** LINE 1 ***
...
end;
...
procedure TfrmARISClient.ServiceNotification(var Msg: TMessage);
begin
TSQLRestClientURI.ServiceNotificationMethodExecute(Msg); //--> *** LINE 2 ***
end;
...
procedure TfrmARISClient.DoOnCallback(const aJSONCallback: RawUTF8);
begin
// process callback in main thread (show progress bar, update labels, etc.)
end;*** LINE 1 ***: use of the client websocket, not of the fARISClient (TSQLRestClientURI/TSQLHttpClient).
*** LINE 2 ***: use of the class procedure of the TSQLRestClientURI, I know I can use fARISClient instead.
in the documentation only show Client.ServiceNotificationMethodViaMessages(MainForm.Handle,WM_SERVICENOTIFICATION) and, for me, is not clear the client type, it may be only me who does not understand.
I hope you understand, anyway this works like a charm.
Regards.
Not exactly, I créate a client with TSQLRestClientURI for communications with the server, but for websocket communications I créate with TSQLHttpClientWebsockets the callbacks and with this instance I call this method, then with TSQLRestClientURI I call the another method (execute). I do not have the code at hand.
@ab, can you clarify in the documentation the use of this method ?
In section 16.7.2.6. Interacting with UI/VCL says:
Client.ServiceNotificationMethodViaMessages(MainForm.Handle,WM_SERVICENOTIFICATION);
and Client is a TSQLHttpClientWebsockets and not TSQLRestClientURI (my silly confusion).
Thanks.
works fine.
Thanks.
Hi @ab, this fix https://synopse.info/fossil/info/f69f5eb7d2ed6541 introduced a bug with error "Invalid point operation".
your fix:
...
ftDate, ftTime, ftDateTime:
if PDateTime(Data)^=0 then
result := false else begin
TS := DateTimeToTimeStamp(PDateTime(Data)^);
if (TS.Time<0) or (TS.Date<=0) then
result := false else // matches ValidateTimeStamp() expectations
case Field.DataType of
ftDate: PDateTimeRec(Dest)^.Date := TS.Date;
ftTime: PDateTimeRec(Dest)^.Time := TS.Time;
ftDateTime: PDateTimeRec(Dest)^.DateTime := TimeStampToMSecs(TS) //-->> YOUR FIX !!!
end;
end;
ftString: begin
...the solution:
...
ftDate, ftTime, ftDateTime:
if PDateTime(Data)^=0 then
result := false else begin
TS := DateTimeToTimeStamp(PDateTime(Data)^);
if (TS.Time<0) or (TS.Date<=0) then
result := false else // matches ValidateTimeStamp() expectations
case Field.DataType of
ftDate: PDateTimeRec(Dest)^.Date := TS.Date;
ftTime: PDateTimeRec(Dest)^.Time := TS.Time;
ftDateTime: PDateTimeRec(Dest)^.DateTime := PDateTime(Data)^; //-->> THE SOLUTION !!!
end;
end;
ftString: begin
...this correction working for me, but I can be wrong.
Best regards.
Maybe this can help you: https://synopse.info/forum/viewtopic.ph … 990#p23990
Thank you very much @ab, I could make it work !! but neither in this life nor any other I could understand the use of this function. Can you update the documentation ?
Anyway, this is an example for any other that need use this function (adapted from example 31):
interface declaration:
...
type
ILongWorkCallback = interface(IInvokable)
['{425BF199-19C7-4B2B-B1A4-A5BE7A9A4748}']
procedure WorkFinished(const workName: string; timeTaken: integer);
procedure WorkFailed(const workName, error: string);
end;
ILongWorkService = interface(IInvokable)
['{09FDFCEF-86E5-4077-80D8-661801A9224A}']
procedure StartWork(const workName: string; const onFinish: ILongWorkCallback);
function TotalWorkCount: Integer;
end;
IAsynchLongWorkService = interface(IInvokable)
['{CFA559E5-B181-45BB-84AB-7279DDDA51A9}']
procedure StartWork(const workName: string; const onFinish: Integer);
end;
...
initialization
TInterfaceFactory.RegisterInterfaces([
TypeInfo(ILongWorkService),TypeInfo(ILongWorkCallback),TypeInfo(IAsynchLongWorkService)]);class declaration:
...
type
TLongWorkService = class(TInterfacedObject,ILongWorkService)
protected
fCallbackInterface: IAsynchLongWorkService;
fDestinationInterface: IAsynchLongWorkService;
public
procedure StartWork(const workName: string; const onFinish: ILongWorkCallback);
function TotalWorkCount: Integer;
end;
TAsynchLongWorkService = class(TInterfacedObject,IAsynchLongWorkService)
protected
fCallback: ILongWorkCallback;
fWorkName: string;
fTotalWorkCount: Integer;
public
procedure StartWork(const workName: string; const onFinish: Integer);
function TotalWorkCount: Integer;
end;
...class implementation:
...
{ TLongWorkAsyncService }
procedure TLongWorkService.StartWork(const workName: string; const onFinish: ILongWorkCallback);
begin
if fCallbackInterface=nil then begin
fDestinationInterface := TAsynchLongWorkService.Create;
ServiceContext.Request.Server.AsynchRedirect(IAsynchLongWorkService,fDestinationInterface,fCallbackInterface);
end;
onFinish._AddRef; // avoid GPF and the interface is available in asynch. routine
fCallbackInterface.StartWork(workName,Integer(onFinish));
end;
function TLongWorkService.TotalWorkCount: Integer;
begin
result := MaxInt; // this shows the asynchronous functioning
end;
...
{ TAsynchLongWorkService }
procedure TAsynchLongWorkService.StartWork(const workName: string; const onFinish: Integer);
var tix: Int64;
begin
InterlockedIncrement(fTotalWorkCount);
fCallback := ILongWorkCallback(onFinish);
fWorkName := workName;
TSQLLog.Add.Log(sllInfo,'%.Execute(%) started',[self,fWorkName]);
tix := GetTickCount64;
Sleep(5000+Random(1000)); // some hard work
if Random(100)>20 then
fCallback.WorkFinished(fWorkName,GetTickCount64-tix) else
fCallback.WorkFailed(fWorkName,'expected random failure');
TSQLLog.Add.Log(sllInfo,'%.Execute(%) notified',[self,fWorkName]);
fCallback._Release; // release the interface out this function
end;
function TAsynchLongWorkService.TotalWorkCount: Integer;
begin
result := fTotalWorkCount;
end;Best regards.
Good, both things are very useful for me, can you give me an example of how call AsynchRedirect, mainly I can't understood the parameters.
procedure AsynchRedirect(const aGUID: TGUID; const aDestinationInterface: IInvokable; out aCallbackInterface); overload;- aGUID: is the source service that I want redirect ? What about the code in the method, must be empty ?
- aDestinationInterface: is any interface where the real process is executed ?
- aCallbackInterface: the aDestinationInterface must have it a callback interface ?
Thanks in advance.
@ab, Is AsynchRedirect working ?
Thanks.
My idea is to implement an asynchronous long work service with the possibility to the cancel it. What would be the best way do it ?
Thanks in advance.
Hi @ab, can you post a simple use of TSQLRest.AsynchRedirect ? I tried but without luck.
Thanks in advance.
I developed TSynRestdataset with Delphi 7 under Windows, for support the any other platform, I do not have the knowledge.
@leus, I'll try that, now I have not time.
Thanks.
@Stemon63, no it is. I documented that I don't know Linux.
@leus, because I tried.
Yes, but I cannot rename/drop folders inside the my folder, I don't know other constraints.
I prefer that when downloading mORMot all things together but as I cannot update the "ThirdParty\EMartin" folder maybe I should use github. I'll put in this thread when I have created the distribution in github.
Best regards.
In this thread, the #60, but the TSynRestdataset is not the problem, maybe you not defined the ORM table or not call CreateMissingTables in the REST server.
Best regards.
Esteban
Hi Stemon63, SynRestDataset use REST/JSON for ORM in a mORMot way, it should work with any mORMot backend through ORM tables.
Best regards.
Esteban.
TSynRestDataset is not experimental, we will release it in production in the next weeks. The TSynRestDataset born into the need the migration three tier legacy software (RemObjects) to more stable application server, I did rewrite all legacy code for total use of mORMot benefits, and in the middle parallel running partial up to total migration.
Best regards.
No, but you can make it visual.
Best regards.
You can try my SynJSONTreeView https://drive.google.com/open?id=0Bx7LP … 0p2eWxNUUE, but not implemented/tested for FPC.
Best regards.
@jbroussia, create a ticket with the problem and the solution, @ab never answered in this thread.