mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +00:00
fhem.pl: async get capability, if supported by the module (Forum #43771)
git-svn-id: https://svn.fhem.de/fhem/trunk@9927 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
67755a6f5b
commit
9d7c346d13
@ -106,6 +106,7 @@ my %FW_types; # device types, for sorting
|
||||
my %FW_hiddengroup;# hash of hidden groups
|
||||
my $FW_inform;
|
||||
my $FW_XHR; # Data only answer, no HTML
|
||||
my $FW_id; # id of current page
|
||||
my $FW_jsonp; # jasonp answer (sending function calls to the client)
|
||||
my $FW_headercors; #
|
||||
my $FW_chash; # client fhem hash
|
||||
@ -125,6 +126,7 @@ FHEMWEB_Initialize($)
|
||||
$hash->{DefFn} = "FW_Define";
|
||||
$hash->{UndefFn} = "FW_Undef";
|
||||
$hash->{NotifyFn}= ($init_done ? "FW_Notify" : "FW_SecurityCheck");
|
||||
$hash->{AsyncOutputFn} = "FW_AsyncOutput";
|
||||
$hash->{ActivateInformFn} = "FW_ActivateInform";
|
||||
no warnings 'qw';
|
||||
my @attrList = qw(
|
||||
@ -475,6 +477,43 @@ FW_Read($$)
|
||||
}
|
||||
}
|
||||
|
||||
sub
|
||||
FW_AsyncOutput($$)
|
||||
{
|
||||
my ($hash, $ret) = @_;
|
||||
|
||||
if( $ret =~ m/^<html>(.*)<\/html>$/s ) {
|
||||
$ret = $1;
|
||||
|
||||
} else {
|
||||
$ret =~ s/&/&/g;
|
||||
$ret =~ s/'/'/g;
|
||||
$ret =~ s/</</g;
|
||||
$ret =~ s/>/>/g;
|
||||
$ret = "<pre>$ret</pre>" if($ret =~ m/\n/ );
|
||||
$ret =~ s/\n/<br>/g;
|
||||
}
|
||||
|
||||
# find the longpoll connection with the same fw_id as the page that was the
|
||||
# origin of the get command
|
||||
my $found = 0;
|
||||
my $data = FW_longpollInfo('JSON',
|
||||
"#FHEMWEB:$FW_wname","FW_okDialog('$ret')","");
|
||||
foreach my $d (keys %defs ) {
|
||||
my $chash = $defs{$d};
|
||||
next if( $chash->{TYPE} ne 'FHEMWEB' );
|
||||
next if( !$chash->{inform} );
|
||||
next if( !$chash->{FW_ID} || $chash->{FW_ID} ne $hash->{FW_ID} );
|
||||
addToWritebuffer($chash, $data."\n");
|
||||
$found = 1;
|
||||
last;
|
||||
}
|
||||
|
||||
$defs{$FW_wname}{asyncOutput}{$hash->{FW_ID}} = $data if( !$found );
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub
|
||||
FW_closeConn($)
|
||||
{
|
||||
@ -601,6 +640,11 @@ FW_answerCall($)
|
||||
}
|
||||
}
|
||||
|
||||
if( $FW_id ) {
|
||||
$me->{FW_ID} = $FW_id;
|
||||
$me->{canAsyncOutput} = 1;
|
||||
}
|
||||
|
||||
if($FW_inform) { # Longpoll header
|
||||
if($FW_inform =~ /type=/) {
|
||||
foreach my $kv (split(";", $FW_inform)) {
|
||||
@ -632,6 +676,12 @@ FW_answerCall($)
|
||||
$FW_headercors.
|
||||
"Content-Type: application/octet-stream; charset=$FW_encoding\r\n\r\n".
|
||||
FW_roomStatesForInform($me, $sinceTimestamp));
|
||||
|
||||
if( my $data = $defs{$FW_wname}{asyncOutput}{$FW_id} ) {
|
||||
addToWritebuffer($me, $data."\n");
|
||||
delete $defs{$FW_wname}{asyncOutput}{$FW_id};
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -692,8 +742,9 @@ FW_answerCall($)
|
||||
# Redirect after a command, to clean the browser URL window
|
||||
if($docmd && !$FW_cmdret && AttrVal($FW_wname, "redirectCmds", 1)) {
|
||||
my $tgt = $FW_ME;
|
||||
if($FW_detail) { $tgt .= "?detail=$FW_detail" }
|
||||
elsif($FW_room) { $tgt .= "?room=$FW_room" }
|
||||
if($FW_detail) { $tgt .= "?detail=$FW_detail&fw_id=$FW_id" }
|
||||
elsif($FW_room) { $tgt .= "?room=$FW_room&fw_id=$FW_id" }
|
||||
else { $tgt .= "?fw_id=$FW_id" }
|
||||
TcpServer_WriteBlocking($me,
|
||||
"HTTP/1.1 302 Found\r\n".
|
||||
"Content-Length: 0\r\n". $FW_headercors.
|
||||
@ -782,7 +833,8 @@ FW_answerCall($)
|
||||
my $csrf= ($FW_CSRF ? "fwcsrf='$defs{$FW_wname}{CSRFTOKEN}'" : "");
|
||||
my $gen = 'generated="'.(time()-1).'"';
|
||||
my $lp = 'longpoll="'.AttrVal($FW_wname,"longpoll",1).'"';
|
||||
FW_pO "</head>\n<body name=\"$t\" $gen $lp $csrf>";
|
||||
$FW_id = $FW_chash->{NR} if( !$FW_id );
|
||||
FW_pO "</head>\n<body name=\"$t\" fw_id=\"$FW_id\" $gen $lp $csrf>";
|
||||
|
||||
if($FW_activateInform) {
|
||||
$cmd = "style eventMonitor $FW_activateInform";
|
||||
@ -874,6 +926,7 @@ FW_digestCgi($)
|
||||
$FW_room = "";
|
||||
$FW_detail = "";
|
||||
$FW_XHR = undef;
|
||||
$FW_id = undef;
|
||||
$FW_jsonp = undef;
|
||||
$FW_inform = undef;
|
||||
|
||||
@ -900,6 +953,7 @@ FW_digestCgi($)
|
||||
if($p eq "pos") { %FW_pos = split(/[=;]/, $v); }
|
||||
if($p eq "data") { $FW_data = $v; }
|
||||
if($p eq "XHR") { $FW_XHR = 1; }
|
||||
if($p eq "fw_id") { $FW_id = $v; }
|
||||
if($p eq "jsonp") { $FW_jsonp = $v; }
|
||||
if($p eq "inform") { $FW_inform = $v; }
|
||||
|
||||
@ -1363,7 +1417,8 @@ FW_roomOverview($)
|
||||
FW_pO "<div id=\"hdr\">";
|
||||
FW_pO '<table border="0" class="header"><tr><td style="padding:0">';
|
||||
FW_pO "<form method=\"$FW_formmethod\" action=\"$FW_ME\">";
|
||||
FW_pO FW_hidden("room", "$FW_room") if($FW_room);
|
||||
FW_pO FW_hidden("fw_id", $FW_id) if($FW_id);
|
||||
FW_pO FW_hidden("room", $FW_room) if($FW_room);
|
||||
FW_pO FW_hidden("fwcsrf", $defs{$FW_wname}{CSRFTOKEN}) if($FW_CSRF);
|
||||
FW_pO FW_textfield("cmd", $FW_ss ? 25 : 40, "maininput");
|
||||
FW_pO "</form>";
|
||||
|
@ -17,6 +17,7 @@ telnet_Initialize($)
|
||||
|
||||
$hash->{DefFn} = "telnet_Define";
|
||||
$hash->{ReadFn} = "telnet_Read";
|
||||
$hash->{AsyncOutputFn} = "telnet_Output";
|
||||
$hash->{UndefFn} = "telnet_Undef";
|
||||
$hash->{AttrFn} = "telnet_Attr";
|
||||
$hash->{NotifyFn}= "telnet_SecurityCheck";
|
||||
@ -187,6 +188,7 @@ telnet_Read($)
|
||||
if($hash->{SERVERSOCKET}) { # Accept and create a child
|
||||
my $chash = TcpServer_Accept($hash, "telnet");
|
||||
return if(!$chash);
|
||||
$chash->{canAsyncOutput} = 1;
|
||||
$chash->{encoding} = AttrVal($name, "encoding", "utf8");
|
||||
$chash->{prompt} = AttrVal($name, "prompt", "fhem>");
|
||||
syswrite($chash->{CD}, sprintf("%c%c%c", 255, 253, 0) )
|
||||
@ -203,6 +205,7 @@ telnet_Read($)
|
||||
if($hash->{isClient}) {
|
||||
telnet_ClientDisconnect($hash, 0);
|
||||
} else {
|
||||
delete $hash->{canAsyncOutput};
|
||||
CommandDelete(undef, $name);
|
||||
}
|
||||
return;
|
||||
@ -284,17 +287,10 @@ telnet_Read($)
|
||||
$ret .= (join("\n", @ret) . "\n") if(@ret);
|
||||
$ret .= ($hash->{prevlines} ? "> " : $hash->{prompt}." ")
|
||||
if($gotCmd && $hash->{showPrompt} && !$hash->{rcvdQuit});
|
||||
if($ret) {
|
||||
$ret = utf8ToLatin1($ret) if( $hash->{encoding} eq "latin1" );
|
||||
$ret =~ s/\n/\r\n/g if($pw); # only for DOS telnet
|
||||
for(;;) {
|
||||
my $l = syswrite($hash->{CD}, $ret);
|
||||
last if(!$l || $l == length($ret));
|
||||
$ret = substr($ret, $l);
|
||||
}
|
||||
$hash->{CD}->flush();
|
||||
|
||||
}
|
||||
$ret =~ s/\n/\r\n/g if($pw); # only for DOS telnet
|
||||
telnet_Output($hash,$ret);
|
||||
|
||||
if($hash->{rcvdQuit}) {
|
||||
if($hash->{isClient}) {
|
||||
delete($hash->{rcvdQuit});
|
||||
@ -304,6 +300,24 @@ telnet_Read($)
|
||||
}
|
||||
}
|
||||
}
|
||||
sub
|
||||
telnet_Output($$)
|
||||
{
|
||||
my ($hash,$ret) = @_;
|
||||
|
||||
if($ret) {
|
||||
$ret = utf8ToLatin1($ret) if( $hash->{encoding} eq "latin1" );
|
||||
for(;;) {
|
||||
my $l = syswrite($hash->{CD}, $ret);
|
||||
last if(!$l || $l == length($ret));
|
||||
$ret = substr($ret, $l);
|
||||
}
|
||||
$hash->{CD}->flush();
|
||||
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
##########################
|
||||
sub
|
||||
|
21
fhem/fhem.pl
21
fhem/fhem.pl
@ -1601,12 +1601,33 @@ CommandGet($$)
|
||||
}
|
||||
|
||||
$a[0] = $sdev;
|
||||
$defs{$sdev}->{CL} = $cl;
|
||||
my $ret = CallFn($sdev, "GetFn", $defs{$sdev}, @a);
|
||||
delete $defs{$sdev}->{CL};
|
||||
push @rets, $ret if(defined($ret) && $ret ne "");
|
||||
}
|
||||
return join("\n", @rets);
|
||||
}
|
||||
|
||||
sub
|
||||
asyncOutput($$)
|
||||
{
|
||||
my ($cl,$ret) = @_;
|
||||
|
||||
return undef if( !$cl );
|
||||
|
||||
if( !$defs{$cl->{NAME}}
|
||||
|| $defs{$cl->{NAME}}->{NR} != $cl->{NR}
|
||||
|| $defs{$cl->{NAME}}->{NAME} ne $cl->{NAME} ) {
|
||||
Log3 $cl->{NAME},3,"$cl->{NAME} asyncOutput: device gone, output was: $ret";
|
||||
return undef;
|
||||
}
|
||||
|
||||
$ret = CallFn($cl->{NAME}, "AsyncOutputFn", $defs{$cl->{NAME}}, $ret);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
LoadModule($;$)
|
||||
|
@ -52,8 +52,8 @@ function
|
||||
FW_jqueryReadyFn()
|
||||
{
|
||||
FW_docReady = true;
|
||||
FW_serverGenerated = document.body.getAttribute("generated");
|
||||
if(document.body.getAttribute("longpoll"))
|
||||
FW_serverGenerated = $("body").attr("generated");
|
||||
if($("body").attr("longpoll"))
|
||||
setTimeout("FW_longpoll()", 100);
|
||||
|
||||
$("a").each(function() { FW_replaceLink(this); })
|
||||
@ -128,6 +128,7 @@ FW_jqueryReadyFn()
|
||||
});
|
||||
FW_cmd(FW_root+"?"+cmd+"&XHR=1&addLinks=1", function(data) {
|
||||
if(!data.match(/^[\r\n]*$/)) // ignore empty answers
|
||||
data = data.replace( '<', '<' );
|
||||
FW_okDialog('<pre>'+data+'</pre>', el);
|
||||
});
|
||||
});
|
||||
@ -146,12 +147,32 @@ FW_jqueryReadyFn()
|
||||
var input = $(this).find("input.maininput");
|
||||
if(!input.length)
|
||||
return;
|
||||
$(this).on("submit", function() {
|
||||
if($(input).val().match(/^\s*shutdown/)) {
|
||||
FW_cmd(FW_root+"?XHR=1&cmd="+$(input).val());
|
||||
$(this).on("submit", function(e) {
|
||||
var val = $(input).val();
|
||||
if(val.match(/^\s*shutdown/)) {
|
||||
FW_cmd(FW_root+"?XHR=1&cmd="+val);
|
||||
$(input).val("");
|
||||
return false;
|
||||
|
||||
} else if(val.match(/^\s*get\s+/)) {
|
||||
// make get use xhr instead of reload
|
||||
//return true;
|
||||
FW_cmd(FW_root+"?cmd="+val+"&XHR=1", function(data) {
|
||||
if( !data.match( /^<html>.*<\/html>/ ) ) {
|
||||
data = data.replace( '<', '<' );
|
||||
data = '<pre>'+data+'</pre>';
|
||||
}
|
||||
if( location.href.indexOf('?') === -1 )
|
||||
$('#content').html(data);
|
||||
else
|
||||
FW_okDialog(data);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
$(input).val("");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
@ -215,7 +236,7 @@ log(txt)
|
||||
function
|
||||
addcsrf(arg)
|
||||
{
|
||||
var csrf = document.body.getAttribute('fwcsrf');
|
||||
var csrf = $("body").attr('fwcsrf');
|
||||
if(csrf && arg.indexOf('fwcsrf') < 0)
|
||||
arg += '&fwcsrf='+csrf;
|
||||
return arg;
|
||||
@ -226,6 +247,7 @@ FW_cmd(arg, callback)
|
||||
{
|
||||
log("FW_cmd:"+arg);
|
||||
arg = addcsrf(arg);
|
||||
arg += '&fw_id='+$("body").attr('fw_id');
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("POST", arg, true);
|
||||
req.send(null);
|
||||
@ -509,7 +531,7 @@ FW_longpoll()
|
||||
filter="room="+room;
|
||||
}
|
||||
}
|
||||
var iP = document.body.getAttribute("iconPath");
|
||||
var iP = $("body").attr("iconPath");
|
||||
if(iP != null)
|
||||
filter = filter +";iconPath="+iP;
|
||||
|
||||
@ -519,6 +541,7 @@ FW_longpoll()
|
||||
|
||||
var query = location.pathname+"?XHR=1"+
|
||||
"&inform=type=status;filter="+filter+";since="+since+";fmt=JSON"+
|
||||
'&fw_id='+$("body").attr('fw_id')+
|
||||
"×tamp="+new Date().getTime();
|
||||
query = addcsrf(query);
|
||||
FW_pollConn.open("GET", query, true);
|
||||
|
Loading…
Reference in New Issue
Block a user