You are not logged in.
Pages: 1
Hi,
I have a custom object registered and it work as expected. Currently one of the functions I'm passing a string but would like to pass an actual javascript object....
function TReceiver.generate_signal(cx: PJSContext; argc: uintN;
var vp: JSArgRec): Boolean;
var
obj : TJsonObject;
panel,
code,
zone : String;
begin
try
if (vp.argv[0].isString)
then begin
obj := TJSONObject.Create;
try
obj.Parse(BytesOf(vp.argv[0].asJSString.ToString(cx)), 0);
panel := TJSONString( obj.GetValue('panel')).value;
code := TJSONString( obj.GetValue('code')).value;
zone := TJSONString( obj.GetValue('zone')).value;
//process parameters
finally
obj.free;
end;
...
right now I'm calling this by wrapping the object within JSON.stringify...
receiver.get_options(
JSON.stringify(`
{
"panel":"1234",
"code":"E130",
"zone":"001",
}
`));
however, I'll like to remove JSON.stringify out of the equation.
receiver.get_options({
"panel":"1234",
"code":"E130",
"zone":"001",
});
Thanks in advance,
Luis
First... Thanks, igors233 for your suggestion!
Second... my bad... The problem was not multi-thread related... It happens that the database I was updating was leaving the connection on 'Suspense' because I tried to alter a table after having a cursor opening the same table... This pretty much locks itself! no good!
Third... something weird I notice is that if I call evaluate within a thread (not been the main thread) it runs, however any loop that have more than 8 repetitions will generate an AV. It could be another bug on my code... It would not surprise me! but it reflects on the engine itself, and I can not even stop the debugger on the code generating the AV... Weird, but it does not happens if the eval runs on the main thread, so no harm, no foul...
Thanks
Luis
Post Message might do the trick (since I'm only adding info to a memo component... emulating the output of console.log).
I can't use Thread.Synchronize because I'm actually "tapping" out of an event... that event seems to be running in a thread other than main. Is not like me creating a TThread instance...
Let me give a try to Post Message!
Hi guys,
I'm doing this small project where the customer can execute JS an application. The application initializes the engine and executes it mostly without problem. The scripting engine does its job, I think the problem is my implementation to extend it.
I created a few classes that provide access to the database from the script... that works perfect, however, there are 2 "utilities" classes that seem to randomly freeze the application half way thru the script. Those classes are done to interact with the main form... And I believe that's where my bug lies.... It behaves like when you access form's components from a thread without synchronizing it. On a threat is easy to fix, because the Sync procedure of TThreat, however here I'm not sure how to sync with the main thread!
Any suggestion?
Luis
Request
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,es;q=0.8
Cache-Control: no-cache
Connection: Upgrade
Host: local.aural9.com
Origin: file://
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: K7iGrAHp7aaHBhoiQG2WAA==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
Response
Date: Sun, 02 Dec 2018 13:12:14 GMT
Transfer-Encoding: chunked
Upgrade: websocket
X-Powered-By: ASP.NET
and the error message is
WebSocket connection to 'ws://localhost/socket.io/chat/' failed: Error during WebSocket handshake: 'Sec-WebSocket-Accept' header is missing
The application does work under this platform, but the web socket does not... I've tried adding/removing web socket from iis, disabling from the web config, but no success yet. Later on I'll post the Chrome headers.
ab wrote:We usually put a nginx server for the TLS (https + wws) process in front of the mORMot web server.
Do you join both https + wss under the same port? or you separate the wss port differently?
Yes, I can (use the same port for WebSocket and normal web server stuff)...
// normal WebSocket stuff...
FProtocol := TWebSocketProtocolEcho.Create('chat','');
FProtocol.OnIncomingFrame := EchoFrame;
FServer.WebSocketProtocols.Add(FProtocol);
// here is where I can plug in my web stuff...
FServer.OnRequest := Process;
My next step is to port WebSnap structure into THttpServer.OnRequest... adjust the use of cookies, query strings, content strings, and headers...
I need to do a few test... but I might try this route first... If this works out, it not only allows me to add websocket, but also improve performance and stability overall on the software.
I've heard good things about nginx, and is in the back of my head, but I'm not too "IT iliterate", and don't want to add more complexity to this project.
I'll post the result sometime early next week!
Tks!
We usually put a nginx server for the TLS (https + wws) process in front of the mORMot web server.
Do you join both https + wss under the same port? or you separate the wss port differently?
Hi everyone...
I have a situation where I already developed a WebSnap app on Delphi. I'm adding a basic Websock to reduce the number of status request. So far so good.
Problem 1... The main connection is https, therefore when Chrome rejects the web socket connection (since is not secured or wss)... so I tried to set up the application behind IIS using URL Rewrite, and the main application answer correctly, however, I can't make it work for the web socket... Even if the main connection is not secure... I could not get URL Rewrite to work... so I tried with ARR... no success either. I've seen some other people doing it with Apache and Nginx, but not so simple on IIS.
Question one...
Have anyone been able to set up the web socket with either URL Rewrite or ARR?
I saw another post describing the use of HttpPlatformHandler (https://synopse.info/forum/viewtopic.php?id=4249
since this would require to modify my application out of WebSnap to implement the THttpServer...
Is there any guidance to port from either webSnap/webBroaker?
Would the WebSocket work on this IIS interface (HttpPlatformHandler)?
Also, since currently the WebSocket use its own component... can I join both regular THttpServer and TWebSocketServer on the same port?
Thanks,
Luis
I was not sure if because is attached to a rooter, it should "inherit" from it... but you are right Orel! Thanks for the heads up!
I wish I read your post before!!!! Thanks thou!
In the short run, and for future reference...
FQuery.Open(vp.argv[0].asJSString.ToString(cx));
loop := 0;
arr := cx.NewRootedObject(cx.NewArrayObject(FQuery.RecordCount-1));
try
while not Fquery.eof do begin
fld := cx.NewObject(nil);
for fldCount := 0 to FQuery.FieldCount -1 do begin
fldName := LowerCase(FQuery.Fields[fldCount].FieldName);
fldValue := FQuery.Fields[fldCount].AsString;
fld.SetProperty(cx, PAnsiChar(fldName), SimpleVariantToJSval(cx,fldValue)) ;
end;
arr.ptr.SetElement(cx, loop, fld.ToJSValue);
inc(loop);
fQuery.Next;
end;
vp.rval := arr.ptr.ToJSValue;
finally
cx.FreeRootedObject(arr);
end;
Hi, I'm trying to create a function that returns a dataset represented in JSON format...
I already have the function returning an array of strings (first field only), instead, I'll like to return a JSON object in its place.
FQuery.Open(vp.argv[0].asJSString.ToString(cx));
loop := 0;
obj := cx.NewRootedObject(cx.NewArrayObject(FQuery.RecordCount-1));
try
while not FQuery.eof do begin
obj.ptr.SetElement(cx, loop, SimpleVariantToJSval(cx, FQuery.Fields[0].AsString)); // add item to arr
inc(loop);
fQuery.Next;
end;
vp.rval := obj.ptr.ToJSValue;;
finally
cx.FreeRootedObject(obj);
end;
In this case, I'm receiving an array with the first field of the selection...
let arr = myfunction('select id,name from customers');
// this returns ['1','2','3','4']
However, I'll like to return something like
let arr = myfunction('select id,name from customers');
// to return returns [{id:'1',name:'Luis'},{id:'2',name:'peter'},{id:'3',name:'Rose'},{id:'4',name:'John'}]
I know I have to loop thru each field and get the field name, what I don't know how to do is to "wrap it" into an object...
FQuery.Open(vp.argv[0].asJSString.ToString(cx));
loop := 0;
obj := cx.NewRootedObject(cx.NewArrayObject(FQuery.RecordCount-1));
try
while not Fquery.eof do begin
// obj.ptr.SetElement(cx, loop, SimpleVariantToJSval(cx, FQuery.Fields[0].AsString)); // add item to arr
for fldCount := 0 to FQuery.FieldCount -1 do begin
fldName := FQuery.Fields[0].FieldName;
fldValue := FQuery.Fields[0].AsString;
// how to wrap it, and add it to the array? <---- Need help!
end;
inc(loop);
fQuery.Next;
end;
vp.rval := obj.ptr.ToJSValue;;
finally
cx.FreeRootedObject(obj);
end;
Thanks in advance,
Luis
I'm assuming the answers are...
- Can I use SyNode and isolate out the "node" part of it, but still use SpiderMonkey 45 or 52?
No... There are plenty of code that seems to be hardcoded attached to external js files (like EvaluateModule('synode.js') or aEng.EvaluateModule('DevTools\Debugger.js'))
- Can I create Delphi function to be called from javascript?
- if yes, can I return a javascript object (based on a record?), meaning the object is not yet defined and will depend on data returned by a dataset
Yes, at least the first part... the second part, I'm not sure, but I can surely return a string and call eval to convert to Javascript Object...
- Can I call javascript functions from Delphi....
Yes
- Can I pass Delphi classes to javascript (like TRequest/TResponse)?
Maybe... you can use delphi class on javascript, not sure if I can pass them as parameters...
Can someone confirm this is correct? or Am I missing something?
I'm looking to introduce the capability to execute javascript into my project. The idea is to allow customers to respond to a web broker server with java script code. However, I'm not looking to support all node related stuff... I would like to keep it simple... plain javascript... trigger a single event, and allow the user to access to a limited number of Delphi classes/functions...
Sample...
- When web broker load, I load from a database a number of javascript "files" and prep the engine...
- on '/plugin' action event of web broker, I'll like to call a function from Delphi to Javascript...
- Inside the Javascript, I'll like the customer to be able to access data by using a Delphi function... something like GetRecord(tableName, recordID)
sample Delphi functions
procedure RegisterWebEvent(pathName:String,functionName:String); // this allow the javascript to self register what event will be responding to
begin
// add information to a tdictionary, or array, or linked list, or anything!
end;
function getRecord(tableName:String;recordID:String):String;
begin
myDataset.sql.text := 'Select * from ' + tableName + ' where id = ' + QuotedStr(recordID);
myDataset.Open;
if not myDataset.EOF then begin
/*
somehow wrap the return into something like...
{
"id":"123",
"name":"Peter",
"age":"54"
}
I know I can loop thru the fieldsDef to create this, but not sure if I should return a string...
*/
end;
end;
sample javascript script
function MyResponse(request, response){
response.content = '<html><body>hello there </body></html>';
}
// call delphi to register
RegisterWebEvent('sayHello','MyResponse');
function getSomeData(request, response){
// access the request object to get a passed parameter
var id = request.contentQuery.values['id'];
// get data by using a delphi code
var myRec = getRecord('Customers','423423');
if (myRec){
response.content = myRec.Name;
}
}
// call delphi to register
RegisterWebEvent('getData','getSomeData');
At this stage, when I receive a '/pluggin' event, I'll check the next path level and see if there is any registered event...
If I receive /pluggin/getData?id=34 I'll call the javascript function getSomeData
That's it... no Node, no debugging, no external modules, no dll, no nothing... just pure javascript...
Questions...
- Can I use SyNode and isolate out the "node" part of it, but still use SpiderMonkey 45 or 52?
- Can I create Delphi function to be called from javascript?
- if yes, can I return a javascript object (based on a record?), meaning the object is not yet defined and will depend on data returned by a dataset
- Can I call javascript functions from Delphi....
- Can I pass Delphi classes to javascript (like TRequest/TResponse)?
tks,
Luis
Updated to the latest (from github) and the problem is still there!
downloaded from https://synopse.info/files/pdf/synpdf.zip
sorry for the late response.... 1.18.1417
going to the file, the last modification was Version 1.18 ( - renamed SQLite3Pages.pas to mORMotReport.pas.....)
but I just downloaded! did I picked up the wrong one!
I assume that's a file version, how can I check my full version?
I dislike to modify someone else code, but by changing this I fixed the problem. I'm sure the code is correct and that I forgot to setup something... but not sure what...
in the procedure TrimLine I changed....
Old code...
if not Fits then // fix API error (too big text) by rough binary approximation
repeat
len := len shr 1;
until (len=0) or Fits;
change to simply...
Fits;
after that modification, my report shows correctly...
any suggestion what I might have done wrong!
Notice how "Log" and "Runners" goes downward (and also how the last character of "Runner" overstep on the next section (columns)
RepObj.DrawText('Log',true);
RepObj.DrawText('Runners',False);
I assume the new line parameter on runners is why the last character is overriding, however, I still can't figure how to draw the text normally
Ups, forgot there is an init section that runs before the posted code....
procedure TReport.InitReport;
begin
RepObj := TGDIPages.Create(FAOwner);
RepObj.BeginDoc;
// header and footer
RepObj.AddTextToHeader('User Access Report');
RepObj.AddLineToHeader(false);
RepObj.AddLineToFooter(false);
RepObj.BeginDoc;
// header and footer
RepObj.AddTextToHeader(FTitle);
if FParamHeader <> '' then begin
RepObj.Font.Size := 8;
RepObj.AddTextToHeader('Params:' + FParamHeader);
end;
RepObj.AddLineToHeader(false);
RepObj.AddLineToFooter(false);
RepObj.Font.Size := 8;
RepObj.Font.Style := [fsItalic];
RepObj.SaveLayout;
RepObj.TextAlign :=taRight;
RepObj.AddTextToFooterAt('Page <<pagenumber>>',RepObj.RightMarginPos);
RepObj.TextAlign :=taJustified;
RepObj.Font.Style := [];
RepObj.RestoreSavedLayout;
RepObj.AddTextToFooter(DateTimeToStr(Now));
end;
probably a newbie issue...
I'm trying to do a report, and columns work great, however when I tried to use DrawText, it seems like the library is doing a new line after each letter!, again no problem when I use DrawTextAcrossCols.
procedure TSignalTicket.Execute;
var
arr_ind : integer;
FData : TData;
FQuery, qSignalDetail : TFDQuery;
n : String;
qry : String;
whr : String;
evts: String;
procedure addWhere(stm : String);
begin
if whr = '' then
whr := ' where (' + stm + ')'
else
whr := whr + ' and (' + stm + ')';
end;
begin
Title := 'Signal Ticket';
inherited;
qry :=
' SELECT c.name AS "Customer", s.utc, ulc.name AS "Classification", s.UL_KEy, s.ul_sounder, s.NAME AS "Site", st.name AS "Type", sr.name AS "Resolution", sh.* FROM SIGNAL_HISTORY sh ' +
' INNER JOIN SIGNAL_TYPES st ON st.id= sh.signal_type ' +
' LEFT JOIN SIGNAL_RESOLUTIONS sr ON sr.id=sh.SIGNAL_RESOLUTION_ID ' +
' INNER JOIN CUSTOMERS c ON c.id=sh.CUSTOMER_ID ' +
' INNER JOIN SITES s ON s.id = sh.SITE_ID ' +
' LEFT JOIN UL_CLASSIFICATIONS ulc ON ulc.id = s.UL_CLASSIFICATION' ;
//addWhere('sh.id = ' + QuotedStr(FParams.Values['signal_id']));
addWhere('sh.id = ' + QuotedStr('3b938dd1-9f34-4ab2-bcc5-b9b9c34c2b15'));
FData := ConnCached.GetDataObj;
try
FQuery := FData.GetQuery;
FQuery.Open(qry + whr);
RepObj.Font.Style := [];
RepObj.AddColumns([10,40,10,40]);
RepObj.DrawTextAcrossCols(['Customer', FQuery.FieldByName('Customer').AsString,'Date', FQuery.FieldByName('dt').AsString]);
RepObj.DrawTextAcrossCols(['Site', FQuery.FieldByName('Site').AsString,'Signal', FQuery.FieldByName('Type').AsString]);
RepObj.DrawTextAcrossCols(['Panel', FQuery.FieldByName('Panel').AsString,'Resolution', FQuery.FieldByName('Resolution').AsString]);
RepObj.DrawTextAcrossCols(['Priority', FQuery.FieldByName('Priority').AsString,'UL Class',FQuery.FieldByName('Classification').AsString]);
RepObj.DrawTextAcrossCols(['Signal', FQuery.FieldByName('Code').AsString,'UL Keys', FQuery.FieldByName('UL_KEY').AsString]);
RepObj.DrawTextAcrossCols(['Zone', FQuery.FieldByName('Zone').AsString,'UL Sounder', IIF(FQuery.FieldByName('UL_SOUNDER').AsString = 't', 'Yes','No' )]);
RepObj.DrawTextAcrossCols(['Active', IIF(FQuery.FieldByName('active').AsString = 't', 'Yes','No' ),'UTC', FQuery.FieldByName('UTC').AsString]);
RepObj.NewLine;
RepObj.ClearColumns;
RepObj.DrawText('Log',true);
RepObj.AddColumns([20,20, 70]);
RepObj.AddColumnHeaders(['Time', 'Operator', 'Description'],true,true);
qSignalDetail := FData.GetQuery;
qSignalDetail.Open(
' SELECT u.name AS "Operator", shd.* FROM SIGNAL_HISTORY_DETAIL shd ' +
' LEFT JOIN USERS u ON shd.user_id = u.id ' +
' where signal_id = ' + QuotedStr(FQuery.FieldByName('ID').AsString) + ' order by dt' );
while not qSignalDetail.Eof do begin
RepObj.DrawTextAcrossCols([
qSignalDetail.FieldByName('dt').AsString,
qSignalDetail.FieldByName('Operator').AsString,
qSignalDetail.FieldByName('data').AsString]);
qSignalDetail.Next;
end;
RepObj.NewLine;
RepObj.DrawText('Runners',False);
RepObj.ClearColumns;
RepObj.AddColumns([15, 16, 16, 4, 4, 4,20]);
RepObj.AddColumnHeaders(['Runner', 'Dispatched', 'Arrived', 'Min','Key','Ver','Notes'],true,true);
qSignalDetail := FData.GetQuery;
qSignalDetail.Open(
' SELECT re.* FROM UL_RUNNER_EVENTS re where signal_id = ' + QuotedStr(FQuery.FieldByName('ID').AsString) + ' order by dispatch_time' );
while not qSignalDetail.Eof do begin
RepObj.DrawTextAcrossCols([
qSignalDetail.FieldByName('name').AsString,
qSignalDetail.FieldByName('dispatch_time').AsString,
qSignalDetail.FieldByName('arrival_time').AsString,
qSignalDetail.FieldByName('ul_travel_time').AsString,
qSignalDetail.FieldByName('key_used').AsString,
qSignalDetail.FieldByName('verification_method').AsString,
qSignalDetail.FieldByName('notes').AsString
]);
qSignalDetail.Next;
end;
RepObj.NewLine;
finally
ConnCached.ReleaseDataObj(FData);
end;
RepObj.EndDoc;
end;
Pages: 1