I've done the SSE functional test!!dakosimo wrote:I will wait. It is not urgent.
Thank you.
Best regards.
Dako.
https://www4.zzz.com.tw/phpBB3/viewtopic.php?f=2&t=358
I've done the SSE functional test!!dakosimo wrote:I will wait. It is not urgent.
Thank you.
Best regards.
Dako.
Yes!! I'm run on mod_harbour!!Otto wrote:Hello,
May I ask if the method "printData()" in the class "TPER" is from your program? Do you run it on Mod Harbour?
Best regards,
Otto
The way mod_harbour is implemented is to insert HTML into the PRG.Otto wrote:Hello,
Thank you. Do you have a sample code?
I am working on a chat application.
I didn't know about Server-Sent Events (SSE) until you mentioned it here.
SSE is a technology that enables real-time communication between a web browser and a server. It allows the server to send events or updates to the client (web page) over a single, long-lived HTTP connection.
SSE can be a more efficient and reliable approach compared to interval requests with AJAX, which is what I currently use.
Would you be willing to share your code?
Best regards,
Otto
Code: Select all | Expand
<?prg
LOCAL cMethod := AP_Method()
LOCAL hParam := hb_hash()
LOCAL hData := hb_hash()
LOCAL i := 0,;
nTolRec := 100,;
nFunc := 0
LOCAL hRes := {;
'err_no'=>0; // 錯誤碼
,'errmsg'=>''; // 錯誤訊息
,'errtil'=>''; // 錯誤抬頭
,'lEnd'=>0; // 結束?<*0:No/1:Yes>
,'step'=>0; // 目前進度指標(every)
,'total'=>0; // 總筆數(total)
}
//
IF cMethod == 'POST'
hParam := AP_PostPairs()
ELSE
hParam := AP_GetPairs()
ENDIF
//
IF hb_hHasKey(hParam, 'func')
nFunc := Val(hParam['func'])
ELSE
nFunc := -1
ENDIF
// AP_RPuts('data method:'+cMethod,'<br>')
IF nFunc == 9
// hData := hb_jsondecode(hParam, 'data')
// 送出 SSE 專用表頭
AP_SetContentType( "Cache-Control: no-cache" ) // 關閉快取
AP_SetContentType( "text/event-stream;charset=UTF-8" ) // 送出表頭格式
//
hRes['step' ] := 0
hRes['total'] := 100
sendMsg( hb_jsonencode( hRes ) )
//
FOR i := 1 To 100
hRes['step' ] := i
hRes['total'] := nTolRec
sendMsg( hb_jsonencode( hRes ) )
NEXT i
hRes['lEnd'] := 1 // 利用此變數通知前端處理完畢!!
sendMsg( hb_jsonencode( hRes ))
RETURN
ENDIF
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>SSE test!!</title>
<meta name="generator" content="WYSIWYG Web Builder 18 - https://www.wysiwygwebbuilder.com">
<link href="test.css" rel="stylesheet">
<link href="index.css" rel="stylesheet">
<script src="jquery-3.6.4.min.js"></script>
<script>
function go(){
let url='index.prg';
let data={
a: 1
,b: 2
};
let param=url+'?func=9&data='+JSON.stringify(data);
alert('Go...');
source = new EventSource(param,{
withCredentials: false // Whether to allow cross domain requests, default: false
});
// Handle postback events 'message'
source.addEventListener('message',function(e){
let o=JSON.parse(e.data); // analyze
if(o.lEnd == 0){ // lEnd=1:End
// Screen display progress processing
let per=Math.round( o.step/o.total*100,2 ); // calculate percentage
$('#progress').val(per);
$('#progress_down').text( per+'%' );
}else{
source.close(); // Close SSE!! Don't send data back!!
//
if(o.err_no != 0){
alert('Failed to read data!!'+o.err_msg, 'Error!!');
return;
}else{
alert('success!!')
}
}
});
// Handle the event on start 'open'
source.addEventListener('open', function(e) {
//
});
// Events when errors are handled 'error'
source.addEventListener('error', function(e) {
if(e.target.readyState == EventSource.CLOSED){
alert('connect be close!!');
source.close(); // stop SSE
}else{
console.log('error!!');
}
});
// Handle system status events 'status'
source.addEventListener('status', function(e) {
console.log('System status is now: ' + e.data);
});
}
</script>
</head>
<body>
<input type="button" id="Button1" onclick="javascript:go();return false;" name="" value="Test" style="position:absolute;left:170px;top:143px;width:132px;height:52px;z-index:0;">
<!-- jquery -->
<label for="" id="progress_down" style="position:absolute;left:0px;top:100px;width:465px;height:35px;line-height:35px;z-index:2;">Text</label>
<span style="color:#000000;font-family:微軟正黑體;font-size:14px;"><strong id="progress_up"><br> Process wait...</strong></span>'
<br><progress id="progress" value="0" max="100" style="height:48px;width:100%;">
<br><label style="text-align:center;width:100%"></label>
</body>
</html>
<?prg
FUNC sendMsg(cRes)
AP_SetContentType( "text/event-stream;charset=UTF-8" ) // 送出表頭格式
AP_RWRITE( e"event: message\n" )
AP_RWRITE( e"id: "+hb_ntos( int( hb_TToMSec( hb_dateTime() )))+e"\n" )
AP_RWRITE( e"retry: 15000\n" ) // 一個整數值,指示斷開連接時的重新連接時間
AP_RWRITE( e"data: "+cRes+e"\n" )
AP_RWRITE( e"\n" ) // 跟上面 hb_eol() 組合成兩個 \n \n 代表送出完畢!!
Delay(50)
AP_RFLUSH()
RETURN NIL
FUNC Delay(nMSec)
LOCAL nSec := hb_TToMSec( hb_dateTime() )
Do While hb_TToMSec( hb_dateTime() ) - nSec < nMSec
// SysRefresh()
hb_releaseCPU()
EndDo
RETURN .T.
?>
Code: Select all | Expand
#include <http_protocol.h>
#include <hbapi.h>
#include <hbapiitm.h>
#include <hbvm.h>
request_rec * GetRequestRec( void );
HB_FUNC( AP_RFLUSH )
{
hb_retni( (int) ap_rflush( GetRequestRec() ) );
}
Code: Select all | Expand
<?php
$hRes=(object)[
'err_no'=>0 // 錯誤碼
,'errmsg'=>'' // 錯誤訊息
,'errtil'=>'' // 錯誤抬頭
,'lEnd'=>0 // 結束?<*0:No/1:Yes>
,'step'=>0 // 目前進度指標(every)
,'total'=>0 // 總筆數(total)
];
$func=(Integer)(isset($_POST["func"]) ? $_POST["func"] : (isset($_GET["func"]) ? $_GET["func"] : -1 ));
if($func == 9){
// hData := hb_jsondecode(hParam, 'data')
// 送出 SSE 專用表頭
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
//
$hRes->step=0;
$hRes->total=100;
sendMsg( json_encode( $hRes ) );
//
for($i=1; $i<=100; $i++){
$hRes->step=i;
$hRes->total=nTolRec;
sendMsg( json_encode( $hRes ) );
}
$hRes->lEnd=1;
sendMsg( json_encode( $hRes ));
return;
}
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>SSE test!!(PHP)</title>
<meta name="generator" content="WYSIWYG Web Builder 18 - https://www.wysiwygwebbuilder.com">
<link href="test.css" rel="stylesheet">
<link href="index_php.css" rel="stylesheet">
<script src="jquery-3.6.4.min.js"></script>
<script>
function go(){
let url='index.prg';
let data={
a: 1
,b: 2
};
let param=url+'?func=9&data='+JSON.stringify(data);
alert('Go...');
source = new EventSource(param,{
withCredentials: false // Whether to allow cross domain requests, default: false
});
// Handle postback events 'message'
source.addEventListener('message',function(e){
let o=JSON.parse(e.data); // analyze
if(o.lEnd == 0){ // lEnd=1:End
// Screen display progress processing
let per=Math.round( o.step/o.total*100,2 ); // calculate percentage
$('#progress').val(per);
$('#progress_down').text( per+'%' );
}else{
source.close(); // Close SSE!! Don't send data back!!
//
if(o.err_no != 0){
alert('Failed to read data!!'+o.err_msg, 'Error!!');
return;
}else{
alert('success!!')
}
}
});
// Handle the event on start 'open'
source.addEventListener('open', function(e) {
//
});
// Events when errors are handled 'error'
source.addEventListener('error', function(e) {
if(e.target.readyState == EventSource.CLOSED){
alert('connect be close!!');
source.close(); // stop SSE
}else{
console.log('error!!');
}
});
// Handle system status events 'status'
source.addEventListener('status', function(e) {
console.log('System status is now: ' + e.data);
});
}
</script>
</head>
<body>
<input type="button" id="Button1" onclick="javascript:go();return false;" name="" value="Test" style="position:absolute;left:170px;top:143px;width:132px;height:52px;z-index:0;">
<!-- jquery -->
<label for="" id="progress_down" style="position:absolute;left:0px;top:100px;width:465px;height:35px;line-height:35px;z-index:2;">Text</label>
<span style="color:#000000;font-family:微軟正黑體;font-size:14px;"><strong id="progress_up"><br> Process wait...</strong></span>'
<br><progress id="progress" value="0" max="100" style="height:48px;width:100%;">
<br><label style="text-align:center;width:100%"></label>
</body>
</html>
<?php
function sendMsg($cRes){
echo "event: message".PHP_EOL;
echo "id: ".time().PHP_EOL;
echo "retry: 15000".PHP_EOL;
echo "data: $cRes".PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
usleep(200);
}
?>
Code: Select all | Expand
body
{
background-color: #FFFFFF;
color: #000000;
font-family: Arial;
font-weight: normal;
font-size: 13px;
line-height: 1.1875;
margin: 0;
padding: 0;
}
#Button1
{
border: 1px solid #2E6DA4;
border-radius: 4px;
background-color: transparent;
background-image: none;
color: #000000;
font-family: Arial;
font-weight: normal;
font-style: normal;
font-size: 16px;
padding: 1px 6px 1px 6px;
text-align: center;
-webkit-appearance: none;
margin: 0;
}
}
#Button1:focus
{
outline: 0;
}
#progress_down
{
border: 0px solid #CCCCCC;
border-radius: 4px;
background-color: transparent;
background-image: none;
color: #000000;
font-family: Arial;
font-weight: normal;
font-style: normal;
font-size: 16px;
margin: 0;
text-align: center;
vertical-align: top;
padding: 4px 4px 4px 4px;
}
#progress_down:focus
{
outline: 0;
}
php version is running but not showing the meter.Error: Unterminated string ''
called from: __PP_PROCESS, line: 0
called from: ..\source\exec.prg, EXECUTE, line: 64
Source:
0062: a: 1
0063: ,b: 2
0064 => };
0065: let param=url+'?func=9&data='+JSON.stringify(data);
0066: alert('Go...');
This seems to be a javascript problem.Otto wrote:Hello ssbbs,
With the prg version I get following error:Error: Unterminated string ''
called from: __PP_PROCESS, line: 0
called from: ..\source\exec.prg, EXECUTE, line: 64
Source:
0062: a: 1
0063: ,b: 2
0064 => };
0065: let param=url+'?func=9&data='+JSON.stringify(data);
0066: alert('Go...');
Code: Select all | Expand
<?prg
:
:
?>
<html>
:
:
</html>
<?prg
:
:
?>
Code: Select all | Expand
function main()
local .....
:
TEMPLATE
<html>
:
:
</html>
ENDTEXT
:
:
:
return