Jump to content

Ron

uniGUI Subscriber
  • Posts

    375
  • Joined

  • Last visited

  • Days Won

    31

Posts posted by Ron

  1. What may work, is using an uniHTMLFrame, containing some

    javascript, where you load a websocket client, which then

    connects to a websocket server you have running, like a nodejs server.

     

    I am in the process of trying this, and I'm going through the various

    websocket js libraries around, and I was able to connect with one

    of them, think it was Faye, to a nodejs server, but there was some other issues,

    so I kept looking. Going to take another closer look in some days.

     

    A list of such libraries is here: https://deepstream.io/blog/realtime-framework-overview/

     

    Maybe it is possible to find a working library - I don't know - some of them use

    their own client libraries, and others use the raw websocket client.

     

    I need to broadcast db changes to all connected clients in real time,

    triggering the client to load the update, if relevant.

  2. You will not need any visual components in the servermodule anyway,

    so any non-visual objects and code you want to share could be in a separate unit

    with only such kind of code, used by both servermodule and mainmodule.

     

    If you have any datasets in mainmodule you want to use, just copy them,

    as well as the connection, and work with separate copies so you have some

    kind of isolation between the server and the client mainmodules.

  3. In several projects I use three db connections:

    - one in the servermodule, just to grab the company name from the db to create the browser page title.

    This connection is closed immediately.

     

    - one in the loginmodule, to take care of login, and this is also closed after login.

    - one in the mainmodule, which connects at create and loads setup values stored in the mainmodule

     

    In one project I have hundreds of datasets with datasources spread on various forms, all linking back to the mainmodule connection.

    This never seems to be an issue. But I have to set the mainmodule database connection for all datasets in the forms' create event,

    to make sure the datasets get the right connection, when there are several available.

     

    But in that project I also have about 70 datasets in the mainmodule, so I guess it's all about being able to maintain some order.

     

    If I get an exception in the servermodule or the mainmodule, like with the db connection, there is no message - that is right.

     

    But I can save the exception message to the db, if that connection works. To get an exception from the servermodule without

    advanced logging, you can use that approach I guess. But as said above - do not try to share that connection. Not without

    some very advanced stuff taking care of unique access, and that is probably not worth it anyway since you can do it from the mainmodule.

     

    I tried to run some heavier routine processing from the servermodule, that is stuff needed for the whole db, like SMS sending.

     

    But I found it to be unreliable, and built a service application instead for that.

     

    It was also easier to maintain this as two separate applications, rather than also have other server processes in the unigui app.

     

    So now I rather create other server applications in addition if specialized server processes are needed,

    rather than trying to put it all in unigui, even if it may seem tempting because of the servermodule being there.

     

    I was trying to run things with timers etc., but the servermodule requires the app to be loaded once before it kicks in, so that

    was another thing to consider. I guess for some simple stuff you can do it from the servermodule, if you are aware of the

    limitations. I am not aware of them all, so there is probably some reason for precaution.

    • Upvote 1
  4. Right, and put it in the servermodule, and in the mainmodule onCreate as well if you need to.

    procedure TUniServerModule.UniGUIServerModuleCreate(Sender: TObject);
    var f:textfile;
        hostLine, portLine, dbLine, dbPortLine:string;
        cmdStr:string;
    
    procedure ExploreWeb(page:PChar);
    var Returnvalue: integer;
    begin
      ReturnValue := ShellExecute(0, 'open', page, nil, nil,SW_SHOWNORMAL);
      if ReturnValue <= 32 then
         begin
         case Returnvalue of
              0 : MessageBox(0,'Error: Out of memory','Error',0);
              ERROR_FILE_NOT_FOUND: MessageBox(0,'Error: File not found','Error',0);
              ERROR_PATH_NOT_FOUND: MessageBox(0,'Error: Directory not found','Error',0);
              ERROR_BAD_FORMAT    : MessageBox(0,'Error: Wrong format in EXE','Error',0);
         else
              MessageBox(0,PChar('Error Nr: '+IntToStr(Returnvalue)+' inShellExecute'),'Error',0)
         end;
      end;
    end;
    
    begin
      ServerRoot:=extractfilepath(GetModuleName(HInstance));
    
      //read setup text file
      try
        assignfile(f, ServerRoot+'files/setup.txt');
        reset(f);
        readln(f, hostLine);
        readln(f, portLine);
        readln(f, dbLine);
        readln(f, dbPortLine);
        closefile(f);
      except
        on E:Exception do ;
      end;
    
      case sslSetup of
        true: begin
          ssl.Enabled:=true;
          port:=443;
        end;
        false:begin
          ssl.Enabled:=false;
          port:=strtointdef(portLine, 8077);
        end;
      end;
    
      //connect db
      try
      with myDb do begin
        username:='user';
        userpassword:='pass';
        host:=hostLine;
        databasename:=dbLine;
        port:=strtointdef(dbPortLine, 3307);
        open;
      end;
      except
        on E:Exception do ;
      end;
    
      //load db setup data
      try
        loadSetup;
      except
        on E:Exception do ;
      end;
    
      //set app title
      title:=myLoadedSetupTitle;
    
      //close this db connection
      myDb.close;
    
      //autostart if standalone
      if self.StandAloneServer then begin
        cmdStr:='http://localhost:'+portLine;
        ExploreWeb(pchar(cmdStr));
      end;
    end;
    
  5. Well, if it's the creation of the form, then is it only the creation of

    visual elements, or is it also the loading of data from db taking time?

     

    If you have data-aware components, notice that it will take some

    time to update them as the queries are opened.

     

    You may improve load time by not using data-aware components

    and also by using direct-sql query components that does not

    convert according to data type, i.e. that delivers only strings

    which you then manually convert if needed and then load into

    visual components

  6. Is it the creation of the form, or the viewing of the form that takes 6 secs?

     

    If you set FreeOnClose to false, open it, close it and open it again, does it still take 6 secs?

     

    If you can define the form as a free form, and somehow create it in the

    background as the app loads, and then just show it when needed, maybe that helps.

  7. Having two apps listening on the same port, on the same IP,

    would create a routing problem, so it is blocked by the OS.

    If both responds, who does first would be unpredictable,

    and it's meant to be a one-on-one setup like in monogamy.

     

    But you can add another network card/IP address on the

    same box, if that helps you.

     

    That way you can broadcast to both apps, on the same port

    but different IP, if that was the goal. Like having two girls,

    but in different rooms. You can't have two open ports in one

    single room...only creates problems....just common sense :)

    • Upvote 1
  8. @soon: yes, the indy http client.

     

    Below is a function I previously used to send SMS via a phone operator web service, using http.get and no ssl:

     

    function TuniMainModule.SendSMS(number, msg:string):string;
    const
      cUSER_AGENT = 'Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)';
    var
     httpResponse: string;
     Stream: TStringStream;
     URL, telParams:string;
     HTTP:TidHTTP;
    begin
      Stream := TStringStream.Create;
      HTTP:=TIdHTTP.Create(nil);
      HTTP.ReadTimeout := 10000;{ IdTimeoutInfinite; }
      HTTP.ConnectTimeout := 10000;
      try
        HTTP.Request.UserAgent := cUSER_AGENT;
        try
          HTTP.Get(URL, Stream);
          result:= Stream.DataString;
        except
          result:= 'SMS Error!';
        end;
      finally
        Stream.Free;
        HTTP.Free;
      end;
    end;
     
    If you want basic http auth then add:
     
    HTTP.Request.BasicAuthentication:=true;
    HTTP.Request.Username:=username;
    HTTP.Request.Password:=pw;
     
    If you need SSL, add:
     
    var
    LHandler: TIdSSLIOHandlerSocketOpenSSL;
    ...
    try
    LHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

    ...

    HTTP.IOHandler:=LHandler;

    finally

    LHandler.Free;

     

    etc.

     

    If you need to POST, use HTTP.Post(url, aParams, aResponse);

     

    Notice: using GET you have to think about encoding, since this is

    part of the URL, but when using POST there is no worry about that.

  9. I don't have an example right now, but a web service is basically just an HTTP server,

    so use any HTTP client and make a call, and read the result, XML or JSON....parse it,

    push it into a table and refresh the query linked to your grid, and there you have it.

     

    I like using the Indy components, the HTTP client is blocking, so use a thread if you

    have to, but it is very easy to set up and there are tons of examples on the net.

  10. Yes, it seems like the left property of the buttons

    gets miscalculated at times, in Chrome, and it depends

    on the width of the messagebox.

     

    In the case where I have a OKCancel setup, if I push the left property

    using JS right after the dialog, the buttons show up in Chrome:

     

    MessageDlg('my message text', mtWarning, mbOKCancel, MyCallBack);

    uniSession.AddJS('document.getElementById("button-1005").style.left = "40px";document.getElementById("button-1008").style.left = "140px";');

     

    But of course they are not necessarily centered, but if the text is fixed,

    it works, and I think I will use this on a couple of instances.

  11. Hi all, 

    thought I should share a test project, where I try to use Unigui

    to make a clone of rt.com with its responsive design. Is it possible?

    So far I've done the top part, or most of it.

     

    Obviously there will be some JS and tweaking, but so far so good.

     

    Included is a mysql db that is required, and you will also need

    MyDAC db components to try it out as it is now - but that can of

    course be changed.

     

    Maybe some things could be fixed in a better way using layout

    system of ExtJS, I do not know. But I think it is possible to create

    a CMS system using Unigui.

     

    Kaj

     

     

    post-980-0-06974600-1471633332_thumb.png

    post-980-0-11669000-1471633335_thumb.png

    post-980-0-44788100-1471633338_thumb.png

    post-980-0-45711300-1471633342_thumb.png

    post-980-0-03741400-1471633348_thumb.png

    post-980-0-22646700-1471633351_thumb.png

    rtclone.zip

    • Upvote 2
  12. I agree with zilav - set up a REST server on the local machine connected to the POS

    which accepts print jobs, and route the print job to the right client by choosing specific local

    machine at login, and have a table linking machine with IP. This is what I will do, as you

    need a totally browser-independent solution.

  13. Are you talking about loading an URL in an UrlFrame, and then trying to

    trigger any events in Unigui from that code?

     

    It seems to me that you then do not have access to the ajaxRequest

    function, so theoretically you could create a new XMLHttpRequest() object,

    if you only knew the URL on the unigui receiving side.

    <html>
    <head>
    </head>
    <body>
    
    <button type="button" onClick="xhr.send(encodeURI('eventname=test'));">Click Me!</button> 
    
    
    <script type="text/javascript">
      xhr =  new XMLHttpRequest();
      xhr.open('GET',encodeURI('[Unigui-urlframe-url]'));
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      
      xhr.onload = function() {
        if (xhr.status === 200 && xhr.responseText !== newName) {
            alert('Something went wrong.  Name is now ' + xhr.responseText);
        }
        else if (xhr.status !== 200) {
            alert('Request failed.  Returned status of ' + xhr.status);
        }
    };
     
      
    </script>
    </body>
    </html> 
  14. If I understand you correctly, you can then use a unihtmlframe and trigger an

    ajaxevent of that frame, from html, using

     

    ajaxRequest(mainform.htmlframe, ['eventname'], { param1: some_info });

     

    and then handle that event and trigger the delphi procedure.

  15. This is an example of cropping an image, using some javascript.

     

    The image is uploaded to the server, and then shown in the htmlframe

    by the JS, and then the crop data is returned to the mainmodule, where

    you can resample the image.

     

    There is a need for better resampling routines, maybe somebody can

    fix that - and if so please uploaded the new version.

     

    Probably needs a little adjustment of the JS too re. moving the cropframe

    if it's maxed out.

     

    The JS is in the cropFrame.HTML, but for JS debugging it is usually

    easier to edit when loaded from a file.

     

     

    There should be another way to do this, where the image is never

    initially uploaded to the server, but stays in the browser only and

    is also resampled in the browser using JS, and then at last uploaded

    to the server. Less data to transport, but a bit more work for the client.

     

     

    post-980-0-34264800-1462717751_thumb.png

    unigui crop.zip

    • Like 3
    • Upvote 2
×
×
  • Create New...