in reply to Re^2: Can two separate responses be sent to the client's browser from Perl, such as via fork{}?
in thread Can two separate responses be sent to the client's browser from Perl, such as via fork{}?

Your server will be sending a JSON:

my $PDF = ...; # read PDF binary contents from file my $LOGSTR = ...; # read LOG file contents use MIME::Base64; my $data = { # this is binary that's why we encode it to fit in a JSON string 'pdf' => encode_base64($PDF), # this is text but it does not harm: 'logstr' => encode_base64($LOGSTR) }; # send the data to client: # CGI version: use CGI qw(:standard); use JSON; print header('application/json'); my $json_text = to_json($data); print $json_text; # OR render JSON to go to client with Mojolicious my $c = ... # controller ... $c->render(json => $data); # $data as above

Here is javascript for the client (more like untested hints):

function ajaxit( url, // server endpoint method, // e.g. POST data // any data to send to the server for this request? ){ var xmlhttp = new XMLHttpRequest(); xhr.open(method, url, true); // this is the function which handles the xhr data transfer xhr.onreadystatechange = function () { // xhr.readyState can be 0 to 4 and each one comes here // 4 means transaction is all done, // 3 means data is received. // for error or success, state is 4 if( xhr.readyState !== 4 ){ // data is being transfered still, wait ... return; } // xhr.readyState=4, all is done, either on error or success: if( xhr.status === 200 ){ // data was received, make it a JS object (basically a hashtable + aka JSON) var data = JSON.parse(xhr.responseText); // check integrity here // ... // handle the data your html must have a div to put the <a>'s // with this adivID json_data_handler(data, adivID); } else { // we did not get a HTTP code 200 OK, // if we have a callback to handle errors, call it if( onError == null ){ console.log("ajaxre() : error, "+method+"ing to '"+url+"':\n +readyState="+xhr.readyState+", status="+xhr.status); } else { # handle failed request #onError(xhr.readyState, xhr.status); } } }; // now do the XHR request with caller-supplied data xhr.send(data); // this call will be handled by the function above // function is asynchronous and leaves here while request is being m +ade } // this is called when XHR was successful and we got data from server // that data was converted to a JS object (see above ajaxit()) // and this data is given here as dataobj // your html should contain a DIV somewhere (whose id you supply) // to add two <a> tags in there for the user to click function json_data_handler( dataobj, divID ){ // we have already sent an XHR request to server // and it gave us back data (as a xhr.responseText) var obj = JSON.parse(data); // do here some checks if this was successful // ... // atob decodes base64 strings to bytes, // var pdf is now the actual binary pdf content var pdf = atob(dataobj['pdf']); var logstr = atob(dataobj['logstr']); // client-side save-as filename, whatever var saveAsFilename = '...'; // do whatever with pdf data var el = document.getElementById(divID); var a = document.createElement("a"); el.appendChild(a); # edit: set the right headers for pdf data #var blob = new Blob([pdf], {type: "octet/stream"}); var blob = new Blob([pdf], {type: "application/pdf"}); # edit: setting an intermediate variable which should be # revoked when not needed anymore with # window.URL.revokeObjectURL(objurl); var objurl = window.URL.createObjectURL(blob); a.href = objurl; a.download = saveAsFilename+'.pdf'; // do the same for logstr // or, since it is text, display it in the div verbatim }

above is totally untested but the idea was tested

Apropos processing latex from Perl, I always use LaTeX::Driver to run latex.

bw, bliako

  • Comment on Re^3: Can two separate responses be sent to the client's browser from Perl, such as via fork{}?
  • Select or Download Code

Replies are listed 'Best First'.
Re^4: Can two separate responses be sent to the client's browser from Perl, such as via fork{}?
by Polyglot (Chaplain) on Oct 19, 2023 at 10:53 UTC
    Bliako,

    I'd ++ that post more than once if the system allowed. You're very kind to provide code examples. Not having worked with JSON before, it may help me a lot. I've already been trying to work out how to do things via the information at the links provided earlier--so far have yet to get the download to initiate via AJAX. I know it must be possible somehow, but it seems the entire page almost needs to refresh to get the download http headers. I don't know. In any case, only when the entire page is submitted does it seem to work, whereas with AJAX the page is not refreshed, only updated in key parts.

    Regarding the module you suggested, I was unaware of it, but have already got something working. From a quick glance at the description, though, I'm uncertain the module would help me. It says: "run_latex Runs the formatter (latex or pdflatex)." I'm not able to use pdflatex (I wish I could, as it allows for microjustification) because I'm needing compatibility with Asian-language scripts. For my use case, only XeLaTeX can do the job. Perhaps this is why I'm rolling my own script for this. Unfortunately, there are no microjustification capabilities for any TeX solution on these Asian scripts (Thai, Lao, Karen, Burmese, etc.). For that, people have to rent the very pricey (for this economy) Adobe InDesign--or else use Microsoft Word. Ugh!

    Blessings,

    ~Polyglot~

      Polyglot

      Regarding the first part, AJAX requests do not need refreshing the client page. Just concentrate on a test JS script where you click a button, it does AJAX request to server and presents some results in a div. Start from there. An important part of this is server-side: sending JSON back to client on an AJAX request. Once you get the individual components working all will fit together niecely. A WORD OF WARNING: obvioulsy the proper way is to hava the server queueing the client requests, processing them at its own time and notifying the clients (via an email, or via the client checking on the server, perhaps via a client-page timed-auto-refresh (see Re: Can two separate responses be sent to the client's browser from Perl, such as via fork{}?) etc.) when results are ready. This is what afoken and fletch are telling you.

      regarding LaTeX::Driver, it can run XeLaTeX too if you pass this parameter: 'format' => 'pdf(xelatex)' at construction time. There are options to specify the bin path.

      bw, bliako

        Regarding the first part, AJAX requests do not need refreshing the client page. Just concentrate on a test JS script where you click a button, it does AJAX request to server and presents some results in a div.

        Yes, this is exactly the problem. I'm familiar with AJAX, having learned several years ago to use it, rolling my own jQuery-free, no module, Javascript routines for this. The problem is that the http headers for a download are not compatible (as far as I can tell) with sending to a single div on a page--the download wants to BE the page. I have yet to get any download dialogue in the browser through an AJAX-initiated request. The only way I have ever gotten it to work is through standard form submission. I guess I'm just ignorant, because I am quite sure there must be a way to do it, but I can't wrap my mind around how to get the browser to download something sent back to a form element on the page via AJAX. If the others were instructing me in how to accomplish this, I haven't grasped it yet.

        Blessings,

        ~Polyglot~