• Publicidad

Ayuda con código Perl + script en JavaScript

Todo lo relacionado con el desarrollo Web con Perl: desde CGI hasta Mojolicious

Ayuda con código Perl + script en JavaScript

Notapor TooRDJ » 2010-06-10 13:21 @598

Hola, un saludos a todos. Soy nuevo en el foro :mrgreen: Quisiera pedirles una ayuda con un código que estoy armando en Perl. El problema es en el siguiente fragmento:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. print "Content-type: text/html\n\n";
  2.  
  3. print<<EOF;
  4. <HTML>
  5. <head>
  6. <style type="text/css">
  7. <!--
  8. .Estilo1 {
  9.         color: #FF0000;
  10.         font-weight: bold;
  11. }
  12. -->
  13. </style>
  14.  
  15. <SCRIPT language=javascript>
  16. mensaje=
  17. '<p align="center">Mensaje 1</p>'+
  18. '<p align="center">Mensaje 2</p>'+
  19. '<p align="center">Mensaje 3</p>'+
  20. '<p align="center">Mensaje 4</p>'
  21.  
  22. line=0
  23. cursor='_'
  24. function teclear(){
  25. if(line==mensaje.length) cursor=''
  26. ttecleado.innerHTML=mensaje.substring(0,line)+cursor
  27. if(line++<mensaje.length) setTimeout("teclear()",0)
  28. }
  29. </SCRIPT>
  30. </head>
  31.  
  32. <body onLoad="teclear();">
  33. <p align="center"><img src="imagen.jpg" width="800" height="212"></p>
  34. <DIV class=layermensaje id=ttecleado ?></DIV>
  35. </body>
  36. </HTML>
  37. EOF
  38.  
  39. system("(sleep 3; rm /tmp/*) &");
  40. print "--- FIN - END ---";
  41.  
  42. exit(1);
  43.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Como podrán ver, es un código con un JavaScript que muestra un texto en estilo máquina de escribir. El problema que tengo es que se ejecuta:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. system("(sleep 3; rm /tmp/*) &");
  2. print "--- FIN - END ---";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

sin antes haber mostrado el ultimo mensaje, que sería el
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. '<p align="center">Mensaje 4</p>'
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Lo que quiero es que después que muestre ese "Mensaje 4" se ejecuten las líneas:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. system("(sleep 3; rm /tmp/*) &");
  2. print "--- FIN - END ---";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Como está, cuando muestra el "Mensaje 1" ya está el "--- FIN - END ---"

Espero me entiendan y me puedan ayudar...

Muchas gracias.
Última edición por TooRDJ el 2010-06-14 21:21 @931, editado 1 vez en total
TooRDJ
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2010-06-10 13:04 @586

Publicidad

Re: Ayuda con código Perl + script en JavaScript

Notapor explorer » 2010-06-10 13:42 @613

Bienvenido a los foros de Perl en Español, TooRDJ.

El problema es el siguiente: el programa Perl envíe la salida del primer print() al servidor web, que irá, poco a poco, enviando esa salida al navegador del usuario, que comenzará a presentar la pantalla cuando disponga de suficiente información. Y ejecutará el JavaScript cuando todo el código esté presente.

Pero el programa de Perl sigue funcionando, y sigue con una llamada system(), que lanza en segundo plano (&) la ejecución de dos comandos. Se supone que debe esperar 3 segundos antes de borrar los ficheros temporales. Pero el control vuelve inmediatamente a Perl (por haber sido lanzado en segundo plano), donde pinta el último print(), y termina.

Lo que puedes hacer es esperar tú los tres segundos, borrar los ficheros, y luego sacar el mensaje de final:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    sleep 3;
    unlink </tmp/*>;
    print "--- FIN - END ---";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

aunque tampoco es garantía de que se haya ejecutado completamente el JavaScript. Algunos navegadores no comienzan a ejecutar el JavaScript hasta que no ven cerrado el canal de comunicaciones con el servidor web. En ese caso, nada más enviar la última cadena de caracteres hacia el navegador del usuario, cierras el STDOUT: close STDOUT; Así, el servidor web informe al navegador de que la página se terminó de enviar. Y deja al programa Perl libre para seguir funcionando.

Lo que no puedes garantizar es que el servidor web le dé tiempo, en esos tres segundos, a mandarlo al usuario, y que la página se presente y que el JavaScript se ejecute. Hay muchos factores que pueden influir en la presentación.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Ayuda con código Perl + script en JavaScript

Notapor TooRDJ » 2010-06-10 23:56 @039

Hola, explorer, muchas gracias por tu respuesta.

Es decir, colocar después del EOF el sleep 3; Quedando así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
EOF
sleep 10;
system("rm /tmp/*) &");
print "--- FIN - END ---";
exit(1);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Sin embargo, me pasa algo extraño, la ejecución de todo se tarda los 10 segundos, después muestra todo. Y sigo con el mismo problema.

Esto lo había pensado. Lo lógico es que se detenga en esa parte hasta que pasen los 10 segundos, pero no lo hace, detiene todo el proceso. ¿Por qué pasará esto? :?
TooRDJ
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2010-06-10 13:04 @586

Re: Ayuda con código Perl + script en JavaScript

Notapor explorer » 2010-06-11 02:57 @164

Es posible que no hayas desactivado la caché de salida.

Coloca

$|++;

al principio del programa, antes del primer print().

Y el final del programa, yo lo dejaría en:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
EOF
sleep 10;
print "--- FIN - END ---";
close STDOUT;
unlink </tmp/*>;
exit(1);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Así, saldría el mensaje de fin al cabo de diez segundos, cerraría el STDOUT para indicar que no voy a imprimir nada más, y luego, tranquilamente, borraría los ficheros temporales.

Un detalle... ese mensaje de FIN no contiene ningún marcado HTML.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Ayuda con código Perl + script en JavaScript

Notapor TooRDJ » 2010-06-11 19:28 @853

explorer, lamentablemente no doy con la solución :? Aquí coloco el código completo con las últimas modificaciones que me recomiendas. Pero no me funciona. Pausa todo.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2. use CGI::Carp qw(fatalsToBrowser);
  3. use CGI;
  4. use Config::General; #modulo
  5.  
  6. my %Input;
  7.  
  8. my $query = new CGI;
  9. my @pairs = $query->param;
  10.  
  11. my $configfile = new Config::General("/etc/config.conf"); #Ruta de fichero a leer
  12. my %config = $configfile->getall;
  13.  
  14. foreach my $pair(@pairs){
  15. $Input{$pair} = $query->param($pair);
  16. }
  17.  
  18. #Directorio donde queremos estacionar los archivos
  19. my $dir = "/tmp";
  20.  
  21. #Array con extensiones de archivos que podemos recibir
  22. my @extensiones = ('gif','jpg','jpeg','bmp','png');
  23.  
  24. recepcion_de_archivo(); #Iniciar la recepcion del archivo
  25.  
  26. #TODO SALIO BIEN
  27. my $nombre_en_servidor = $Input{'archivo'};
  28. $nombre_en_servidor =~ s/ /_/gi;
  29. $nombre_en_servidor =~ s!^.*(\\|\/)!!;
  30.  
  31. my $ip_local = $config{'LOCAL_IPADDR'}; #LOCAL_IPADDR
  32. $ip_local =~ s/\'//g; #QUITO LOS ACENTOS
  33.  
  34. my $port = $config{'PORT'}; #PORT
  35. $port =~ s/\'//g; #LE QUITO LOS ACENTOS
  36.  
  37. my $languaje = $config{'LANGUAGE'}; #LANGUAGE
  38. $languaje =~ s/\'//g; #LE QUITO LOS ACENTOS
  39.  
  40. $|++;
  41. print "Content-type: text/html\n\n";
  42. print<<EOF;
  43. <HTML>
  44. <head>
  45. <style type="text/css">
  46. <!--
  47. .Estilo1 {
  48.         color: #FF0000;
  49.         font-weight: bold;
  50. }
  51. -->
  52. </style>
  53.  
  54. <SCRIPT language=javascript>
  55. mensaje=
  56. '<p align="center">Mensaje 1</p>'+
  57. '<p align="center">Mensaje 2</p>'+
  58. '<p align="center">Mensaje 3</p>'+
  59. '<p align="center">Mensaje 4</p>'
  60.  
  61. line=0
  62. cursor='_'
  63. function teclear(){
  64. if(line==mensaje.length) cursor=''
  65. ttecleado.innerHTML=mensaje.substring(0,line)+cursor
  66. if(line++<mensaje.length) setTimeout("teclear()",0)
  67. }
  68. </SCRIPT>
  69. </head>
  70.  
  71. <body onLoad="teclear();">
  72. <p align="center"><img src="logo.jpg" width="800" height="212"></p>
  73. <DIV class=layermensaje id=ttecleado ?></DIV>
  74. </body>
  75. </HTML>
  76. EOF
  77.  
  78. sleep 30;
  79. print "--- FIN - END ---";
  80. close STDOUT;
  81. unlink </tmp/*>;
  82. exit(1);
  83.  
  84. sub recepcion_de_archivo{
  85.  
  86. my $nombre_en_servidor = $Input{'archivo'};
  87. $nombre_en_servidor =~ s/ /_/gi;
  88. $nombre_en_servidor =~ s!^.*(\\|\/)!!;
  89.  
  90. my $extension_correcta = 0;
  91.  
  92. foreach (@extensiones){
  93. if($nombre_en_servidor =~ /\.$_$/i){
  94. $extension_correcta = 1;
  95. last;
  96. }
  97. }
  98.  
  99. if($extension_correcta){
  100.  
  101. #Abrimos el nuevo archivo
  102. open (OUTFILE, ">$dir/$nombre_en_servidor") || die "No se puedo crear el archivo";
  103. binmode(OUTFILE); #Para no tener problemas en Windows
  104.  
  105. #Transferimos byte por byte el archivo
  106. while (my $bytesread = read($Input{'archivo'}, my $buffer, 1024)) {
  107. print OUTFILE $buffer;
  108. }
  109.  
  110. #Cerramos el archivo creado
  111. close (OUTFILE);
  112.  
  113. }else{
  114. print "Content-type: text/html\n\n";
  115. print "<h1>Extension incorrecta</h1>";
  116. print "Sólo se reciben archivo con extension:";
  117. print join(",", @extensiones);
  118. exit(0);
  119. }
  120.  
  121. } #sub recepcion_de_archivo
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

¿Qué hago mal?
TooRDJ
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2010-06-10 13:04 @586

Re: Ayuda con código Perl + script en JavaScript

Notapor explorer » 2010-06-12 12:15 @552

Primero, tendría que quedar claro qué es lo que pretendes hacer.

Por el código, parece que el usuario va a subir una imagen, que guardarás en un directorio; luego, obtendrás una serie de datos, como la IP y el puerto; luego, mostrarás una página con el efecto de tecleo; y, finalmente, eliminar todos los ficheros del directorio temporal.

Este último paso es el que no entiendo: si estás usando el módulo CGI, es el propio módulo el que se encarga de eliminar el fichero subido del directorio temporal, en cuanto se termina el programa: tú no tienes que hacer nada para que se borre. Si quieres aumentar la seguridad, puedes agregar la opción -private_tempfiles para aumentar más las opciones de seguridad en el borrado de los ficheros temporales, pero solo es una medida de seguridad extrema: el fichero seguirá siendo borrado al final de la ejecución.

use CGI qw(:standard -private_tempfiles);

Lo que tampoco entiendo es porqué quieres enviar un print() después de los 30 segundos. Si no existiera ese print(), se podrían cerrar los canales estándar más rápido, y así dar la oportunidad de que la página se presente antes.

Esta versión sí que envía toda la página, cierra los canales, y permite seguir ejecutando el cgi.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use CGI       ':standard';
  7. use CGI::Carp 'fatalsToBrowser';
  8.  
  9. $|++; # no caché
  10.  
  11. my $estilo_css = <<END_CSS;
  12. <!--
  13. .Estilo1 {
  14.     color: #FF0000;
  15.     font-weight: bold;
  16. }
  17. -->
  18. END_CSS
  19.  
  20. my $javascript = <<END_JS;
  21. var mensaje =
  22.     'Mensaje 1.' +
  23.     'Mensaje 2.' +
  24.     'Mensaje 3.' +
  25.     'Mensaje 4.'
  26.     ;
  27. var largo = mensaje.length - 1;
  28. var i = 0;
  29. var cursor = '_';
  30. function teclear() {
  31.     if (i == largo) cursor = '';
  32.  
  33.     var ttecleado = document.getElementById("ttecleado");
  34.     var texto     = ttecleado.innerHTML;
  35.     var letra     = mensaje.charAt(i);
  36.  
  37.     texto = texto.substring(0,texto.length -1);
  38.  
  39.     if (letra == '.') {
  40.         ttecleado.innerHTML = texto + '<br />' + cursor;
  41.     }
  42.     else {
  43.         ttecleado.innerHTML = texto + letra    + cursor;
  44.     }
  45.  
  46.     if (i++ < largo) setTimeout("teclear()",100);
  47. }
  48. END_JS
  49.  
  50. print
  51.     header(),
  52.  
  53.     start_html(
  54.         -title  => 'Mi pagina web',
  55.         -style  => {
  56.                      -code => $estilo_css,
  57.                    },
  58.         -script => {
  59.                      -type => 'text/javascript',
  60.                      -code => $javascript,
  61.                    },
  62.         -onLoad => "setTimeout('teclear()', 0)",
  63.     ),
  64.  
  65.     p({-align=>'center'},
  66.         img({-src => 'logo.gif', -width => 800, -height => 212}), br,
  67.         'Bienvenidos',
  68.     ),
  69.  
  70.     div({-class => 'Estilo1', -align=> 'center', -id => 'ttecleado'}
  71.     ),
  72.  
  73.     end_html(),
  74.     ;
  75.  
  76. open my $oldout, ">&STDOUT";    # Duplicamos el canal de salida para que el system() funcione
  77.  
  78. close STDOUT;   # cerramos los canales para indicar fin de salida
  79. close STDERR;   # con estos dos primeros sería suficiente
  80. close STDIN;    # pero cerramos la entrada estándar para estar más seguros
  81.  
  82. system("(sleep 30; rm -f /tmp/*) &");  # ejecución en segundo plano
  83.  
  84. exit(1);
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Hay muchas limitaciones en cuanto cierras los canales de comunicaciones. Quiero decir que no puedes hacer un sleep 30; desde Perl, porque requiere que algunos de esos canales estén abiertos.

Ahora ya es posible ejecutar el system() con operaciones en segundo plano, mientras la página está completamente enviada y funcionando.

Seguro que se me ha pasado algo y se podría realizar de alguna otra manera, como por ejemplo, con fork(), como se comenta aquí.

Los cambios principales con tu programa son:
* ';' en los finales de líneas en el código JavaScript
* ahora en la salida del texto en JavaScript no se ven los caracteres que forman parte del código HTML. Lo que se hace es analizar cada carácter y si es un '.' se traduce por un br.
* generación de código HTML usando las funciones importadas desde CGI. Puede parecer un poco más largo, pero evitas algunos errores de escritura, como los que tienes en el <div>, que le faltan comillas a los atributos y sobra una '?'. Y header() me saca el Content-Type.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Ayuda con código Perl + script en JavaScript

Notapor TooRDJ » 2010-06-12 15:38 @693

Hola, explorer. Seria sleep 3, no 30. Estaba haciendo pruebas por eso estaba el 30 :mrgreen:

Lo que quiero es que después del:

system("(sleep 3; rm -f /tmp/*) &");

se muestre un mensaje a la par con el comando, es decir, termina el Mensaje 4, después viene sleep 3... y por último

--- FIN - END ---

para decir que todo salió bien... El problema que tengo con el código que coloqué, es que me muestra todo de golpe. No termina de mostrar el Mensaje 1 y ya está el texto de --- FIN - END ---

El texto de modo máquina de escribir lo hace bien.

Este código es para subir un archivo al sistema, descomprime en /tmp, ejecuta algunos sh y borra todo lo de la carpeta /tmp.

El problema en sí es ese. Quiero enviar un mensaje para informar que todo salió bien, pero me muestra todo de golpe.
TooRDJ
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2010-06-10 13:04 @586

Re: Ayuda con código Perl + script en JavaScript

Notapor explorer » 2010-06-12 20:47 @907

Si se trata de ir indicando un proceso que lleva mucho tiempo, pero se puede dividir en tareas, se puede ir informando al usuario de lo que va ocurriendo. Entonces, se puede simplificar mucho el problema:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use CGI       ':standard';
  7. use CGI::Carp 'fatalsToBrowser';
  8.  
  9. $|++; # no cache
  10.  
  11. print
  12.     header(),
  13.     start_html('Mi pagina web'),
  14.     p({-align=>'center'}, 'Bienvenidos', ),"\n",
  15.     ;
  16.  
  17. # Comienzo del proceso
  18. print p('Fichero recibido'), "\n";
  19.  
  20. sleep 4;
  21.  
  22. print p('Fichero descomprimido'), "\n";
  23.  
  24. sleep 3;
  25.  
  26. print p('Proceso realizado'), "\n";
  27.  
  28. sleep 2;
  29.  
  30. print p('Limpieza'), "\n";
  31.  
  32. sleep 1;
  33.  
  34. print p('-- FIN --'), "\n";
  35.  
  36. print end_html();
  37.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

El truco está en la variable $| y en los "\n".

Pero... la desventaja está en que esto es muy dependiente del navegador. En mi Firefox suelen salir las dos primeras líneas de golpe, y luego el resto sale bien.

En el enlace que te pasé antes, lleva a un artículo de Randal L. Schwartz donde da una solución mucho más elaborada, usando fork() y CGI::Session, pero mucho más perfecta, porque se crea un proceso aparte que realiza el trabajo largo, mientras que la página generada se va refrescando de forma automática, actualizando el estado en que se encuentra el proceso.

Es mucho más complejo de realizar, pero el resultado es mucho más completo para el usuario, porque siempre se le entrega un HTML completo, y con la información más actual.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Ayuda con código Perl + script en JavaScript

Notapor TooRDJ » 2010-06-14 21:19 @930

explorer, Muchas Gracias... No usaré el script de máquina de escribir. Lo haré como lo colocaste, mensaje por mensaje. Ya lo adapté al code y trabaja muy bien :mrgreen:

¡Saludos...!
TooRDJ
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2010-06-10 13:04 @586

Re: Ayuda con código Perl + script en JavaScript

Notapor adrolmar » 2010-08-13 03:18 @179

Hola,
¿algo parecido que se pueda hacer en PHP para ir mostrando mensajes de estado de un proceso muy largo?

Saludos
adrolmar
 


Volver a Web

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 8 invitados

cron