#1 SyNode » How to pass a javascript object? » 2019-06-07 21:41:18

mrluis
Replies: 0

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

#2 Re: SyNode » Sync to main thread » 2019-02-10 18:49:04

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

#3 Re: SyNode » Sync to main thread » 2019-02-07 19:39:44

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!

#4 SyNode » Sync to main thread » 2019-02-07 16:18:27

mrluis
Replies: 3

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

#5 Re: mORMot 1 » Guidance with IIS » 2018-12-02 18:34:21

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

#6 Re: mORMot 1 » Guidance with IIS » 2018-12-02 15:41:51

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.

#7 Re: mORMot 1 » Guidance with IIS » 2018-12-01 22:04:51

mrluis wrote:
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!

#8 Re: mORMot 1 » Guidance with IIS » 2018-12-01 21:23:31

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?

#9 mORMot 1 » Guidance with IIS » 2018-12-01 19:58:51

mrluis
Replies: 6

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

#10 Re: SyNode » How to return an array of JSON object... » 2018-12-01 18:59:41

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!

#11 Re: SyNode » How to return an array of JSON object... » 2018-11-14 19:34:10

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;

#12 SyNode » How to return an array of JSON object... » 2018-11-13 16:56:11

mrluis
Replies: 4

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

#14 Re: Other components » Newbee question... SyNode » 2017-09-19 17:32:44

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?

#15 Other components » Newbee question... SyNode » 2017-09-12 02:04:52

mrluis
Replies: 2

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

#16 Re: Other components » (TGDIPages) DrawText display the text vertically instead of horizontal » 2017-08-21 23:31:58

Updated to the latest (from github) and the problem is still there!

#19 Re: Other components » (TGDIPages) DrawText display the text vertically instead of horizontal » 2017-08-21 10:28:55

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!  neutral

I assume that's a file version, how can I check my full version?

#20 Re: Other components » (TGDIPages) DrawText display the text vertically instead of horizontal » 2017-08-20 20:45:15

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!

#22 Re: Other components » (TGDIPages) DrawText display the text vertically instead of horizontal » 2017-08-20 17:51:47

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

FluxBB bbcode test

#23 Re: Other components » (TGDIPages) DrawText display the text vertically instead of horizontal » 2017-08-20 17:43:48

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;

#24 Other components » (TGDIPages) DrawText display the text vertically instead of horizontal » 2017-08-20 17:41:47

mrluis
Replies: 11

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;

Board footer

Powered by FluxBB