SSE example
SSE example
Is it possible to use Server-Sent-Events in Mod-harbour and Mercury ? How to define and use EventSource ?
I did not find any example in mod_harbour_samples.
On Internet there are samples for PHP, but I do not know how to realize it using Mercury. I made this view:
{{ View( 'head.view' ) }}
<body>
<h1>Testing SSE</h1>
<div id="result">
</div>
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("servtime.prg");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
};
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>
In servtime.prg I have:
FUNCTION Servtime()
LOCAL stime = TIME()
AP_RPuts( stime )
RETURN NIL
Servtime.prg I put in document root, in place where index.prg exists also.
On display I only get Testing SSE as header text, but no time.
Thank you and Best regards.
Dako.
I did not find any example in mod_harbour_samples.
On Internet there are samples for PHP, but I do not know how to realize it using Mercury. I made this view:
{{ View( 'head.view' ) }}
<body>
<h1>Testing SSE</h1>
<div id="result">
</div>
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("servtime.prg");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
};
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>
In servtime.prg I have:
FUNCTION Servtime()
LOCAL stime = TIME()
AP_RPuts( stime )
RETURN NIL
Servtime.prg I put in document root, in place where index.prg exists also.
On display I only get Testing SSE as header text, but no time.
Thank you and Best regards.
Dako.
- Antonio Linares
- Site Admin
- Posts: 42393
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Has thanked: 9 times
- Been thanked: 41 times
- Contact:
Re: SSE example
Dako,
It is not implemented yet and it may work on the mod_harbour fastCGI version only
We are studying the way to implement it
It is not implemented yet and it may work on the mod_harbour fastCGI version only
We are studying the way to implement it
Re: SSE example
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
line ID: ssbbstw
WeChat ID: ssbbstw
WeChat ID: ssbbstw
- Otto
- Posts: 6396
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 8 times
- Been thanked: 1 time
- Contact:
Re: SSE example
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
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
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
Re: SSE example
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 TPER is a CLASS I wrote for mod_harbour implementation in the backend.
line ID: ssbbstw
WeChat ID: ssbbstw
WeChat ID: ssbbstw
- Otto
- Posts: 6396
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 8 times
- Been thanked: 1 time
- Contact:
Re: SSE example
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
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
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
Re: SSE example
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
The way I implement mod_harbour is to include PRG in HTML.
The implementation is just like PHP, so you have to modify the example code.
I test it and httpd.exe cpu loading is 0%~0.5% only.
demo file download:
https://is.gd/lyVHyf
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() ) );
}
line ID: ssbbstw
WeChat ID: ssbbstw
WeChat ID: ssbbstw
- Otto
- Posts: 6396
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 8 times
- Been thanked: 1 time
- Contact:
Re: SSE example
Hello ssbbs,
Thank you very much for that.
I will study and test your code.
I'm glad to hear that you're using mod_harbour APACHE and that it's working fine for you.
I want to remember that this question has been bothering me a lot:
The way mod_harbour is implemented is by inserting HTML into the PRG.
The way I implement mod_harbour is by embedding PRG into HTML.
Everything with mod_harbour is so new, and there is so much to learn. But it's really fun.
Thanks again for your help.
Best regards from Austria.
LG
Otto
Thank you very much for that.
I will study and test your code.
I'm glad to hear that you're using mod_harbour APACHE and that it's working fine for you.
I want to remember that this question has been bothering me a lot:
The way mod_harbour is implemented is by inserting HTML into the PRG.
The way I implement mod_harbour is by embedding PRG into HTML.
Everything with mod_harbour is so new, and there is so much to learn. But it's really fun.
Thanks again for your help.
Best regards from Austria.
LG
Otto
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
Re: SSE example
Now there is one more important question!
It takes 2xxms to load a .prg each time, but only 5xms for php with the same function.
It takes 2xxms to load a .prg each time, but only 5xms for php with the same function.
line ID: ssbbstw
WeChat ID: ssbbstw
WeChat ID: ssbbstw
- Otto
- Posts: 6396
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 8 times
- Been thanked: 1 time
- Contact:
Re: SSE example
Hello ssbbs,
I believe it is important to appreciate the functionality of the server-side program. In my case, since I am using DBF, I require mod Harbour.
Currently, without SSE (Server-Sent Events), I utilize `setInterval()`, which is similar to `timer()` in Harbour. Then, I use `fetch` to check if there is any new data on the server.
Best regards,
Otto
myInterval = setInterval(LoadItems, 3000);
function LoadItems() {
let recipients = {
"recipient1": document.getElementById("nav_recip1").checked,
"miterledigt": document.getElementById("nav_miterledigt").checked,
};
fetch("chat.prg?items=" + ctime, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(recipients)
})
.then(res => {
if (res.ok) {
return res.text();
} else {
throw new Error(res.status + " " + res.statusText);
}
}).then(data => {
intervalcounter += 1
console.log("LoadItems data");
console.log(intervalcounter);
if (intervalcounter === 20) {
clearInterval(myInterval);
alert("Aktualisierung pausiert.");
intervalcounter = 0;
myInterval = setInterval(LoadItems, 3000);
}
if (data.startsWith("stop")) {
clearInterval(myInterval);
alert("beendet");
}
if (tmpdata != data) {
document.getElementById('browse').innerHTML = data;
scrollToBottom("browse");
tmpdata = data;
}
});
}
I believe it is important to appreciate the functionality of the server-side program. In my case, since I am using DBF, I require mod Harbour.
Currently, without SSE (Server-Sent Events), I utilize `setInterval()`, which is similar to `timer()` in Harbour. Then, I use `fetch` to check if there is any new data on the server.
Best regards,
Otto
myInterval = setInterval(LoadItems, 3000);
function LoadItems() {
let recipients = {
"recipient1": document.getElementById("nav_recip1").checked,
"miterledigt": document.getElementById("nav_miterledigt").checked,
};
fetch("chat.prg?items=" + ctime, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(recipients)
})
.then(res => {
if (res.ok) {
return res.text();
} else {
throw new Error(res.status + " " + res.statusText);
}
}).then(data => {
intervalcounter += 1
console.log("LoadItems data");
console.log(intervalcounter);
if (intervalcounter === 20) {
clearInterval(myInterval);
alert("Aktualisierung pausiert.");
intervalcounter = 0;
myInterval = setInterval(LoadItems, 3000);
}
if (data.startsWith("stop")) {
clearInterval(myInterval);
alert("beendet");
}
if (tmpdata != data) {
document.getElementById('browse').innerHTML = data;
scrollToBottom("browse");
tmpdata = data;
}
});
}
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
Re: SSE example
No! What my mean is: the time it takes for the client to receive a .prg file from the host!!
Receiving index.prg file from host takes 262ms.
Receiving index.prg file from host takes 262ms.
line ID: ssbbstw
WeChat ID: ssbbstw
WeChat ID: ssbbstw
- Otto
- Posts: 6396
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 8 times
- Been thanked: 1 time
- Contact:
Re: SSE example
Hello ssbbs,
I understand.
Can you please post the php code, too.
Best regards,
Otto
I understand.
Can you please post the php code, too.
Best regards,
Otto
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
Re: SSE example
index_php.php:
index_php.css
result:
gif:
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;
}
gif:
line ID: ssbbstw
WeChat ID: ssbbstw
WeChat ID: ssbbstw
- Otto
- Posts: 6396
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 8 times
- Been thanked: 1 time
- Contact:
Re: SSE example
Hello ssbbs,
thank you.
With the prg version I get following error:
Maybe you can help me once more.
Best regards,
Otto
thank you.
With the prg version I get following error:
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...');
Maybe you can help me once more.
Best regards,
Otto
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************