Thread: [Cppcms-users] How to combine SSE with the url dispatcher
Brought to you by:
artyom-beilis
|
From: eric m. <mid...@gm...> - 2014-02-22 10:20:26
|
Hello, I'm trying to combine the features of the ticker example ( https://svn.code.sf.net/p/cppcms /code/framework/trunk/contrib/server_side/sse/), i.e. streaming data from the server to update a webpage with url dispatching instead of using the default main function and a static html page. So instead of the following code in ticker.cpp: void main(std::string /*url*/) { stream_->accept(release_context()); } I would like to use something like: MyApp::MyApp(cppcms::service &service) : cppcms::application(service), tm_(service.get_io_service()), price_(1.0) { dispatcher().assign("/camerasettings",&MyApp::cameraSettings,this); mapper().assign("Camera Settings","/camerasettings"); mapper().root("/robot"); stream_ = sse::state_stream::create(service.get_io_service()); wait(); } void MyApp::cameraSettings() { string page = FileSystem().readFileIntoString("the_ticker.html"); response().out() << page.c_str(); stream_->accept(release_context()); } While having all the rest the same as in the ticker example. I open the page with 127.0.0.1:8080/robot/camerasettings and the page is displayed correctly but the stream keeps loading and is not being displayed. After stopping the server, the data is displayed and looks like this: Stock Price Price: id:8 data:2.54208 id:9 data:2.97668 id:10 data:3.19061 id:11 data:2.67639 id:12 data:3.28474 id:13 data:3.08663 id:14 data:2.30425 id:15 data:1.74076 id:16 data:2.41898 id:17 data:2.01105 id:18 data:2.05962 id:19 data:3.00517 id:20 data:3.54789 id:21 data:4.08772 id:22 data:4.87077 id:23 data:4.57569 id:24 data:5.41374 id:25 data:6.3124 If on the other hand the stream is accepted before the response is sent, like this void MyApp::cameraSettings() { string page = FileSystem().readFileIntoString("the_ticker.html"); stream_->accept(release_context()); response().out() << page.c_str(); } an exception is thrown: cppcms, error: Caught exception [Access to unassigned context] which seems to be kind of logical, the page does not show, but after stopping the server, the browser displays the streamed data as follows: id:15 data:1.74076 id:16 data:2.41898 id:17 data:2.01105 id:18 data:2.05962 id:19 data:3.00517 id:20 data:3.54789 So I have two questions: 1) How do I combine server side events with url dispatching in cppcms? As I would like to create and send the page to the browser from a method and start to stream events after the page has loaded. 2) How do I stop the stream if the user switches to another page or does it stop itself? I can provide full sourcecode if necessary. Sofar I couldn't find other comparable examples. My guess is that it shouldn't be all that difficult once you know, but currently I do not (-; Any help is welcome here. Best regards, Eric |
|
From: Marcel H. <ke...@co...> - 2014-02-22 12:02:34
Attachments:
signature.asc
|
On 22.02.2014 11:20, eric middelkoop wrote:
> Hello,
Hi Eric,
> While having all the rest the same as in the ticker example.
>
> I open the page with 127.0.0.1:8080/robot/camerasettings
> <http://127.0.0.1:8080/robot/camerasettings> and the page is displayed
> correctly but the stream keeps loading and is not being displayed. After
> stopping the server, the data is displayed and looks like this:
>
I think you still haven't fully understood the concept of streams. A
stream is a non-ending flow of information.
Therefore your browser cannot display the infos except the stream has
been closed (you stopped the server), because it doesn't know if there
is anything left to display (and it is indeed).
So what you are missing is a html page like the_ticker.html with
javascript inside, that opens the stream and gets the needed
information. I think you should look at 'the_ticker.html' a second time,
especially the javascript part.
>
> void MyApp::cameraSettings()
> {
> string page = FileSystem().readFileIntoString("the_ticker.html");
> stream_->accept(release_context());
> response().out() << page.c_str();
> }
I don't know what you are trying, but it's getting wrong ;)
> So I have two questions:
>
> 1) How do I combine server side events with url dispatching in cppcms? As I would like to create and send the page to the browser from a method and start to stream events after the page has loaded.
Hmmm, you should (if it's possible) let the stream run from the
beginning of your application. That's how it should work. The
dispatching is the same as in every other application. You have a method
that creates a page with response().out() << "foo" or with a template.
It's up to you.
>
> 2) How do I stop the stream if the user switches to another page or does it stop itself?
As I said, you should not.
>
> I can provide full sourcecode if necessary. Sofar I couldn't find other comparable examples.
>
> My guess is that it shouldn't be all that difficult once you know, but currently I do not (-;
>
If you really need to start and stop the stream, I *think* it should
work via [0]. You mount a asynchronous application and as soon the
pointer becomes 'illegal' the application will be dismounted. Maybe you
should look at that, but I think Artyom can help here more than I can.
Maybe he'll clarify this.
Greetings
[0]
http://cppcms.com/cppcms_ref/latest/classcppcms_1_1applications__pool.html#a5df195e454c857c4c064f8593c76fc45
|
|
From: Marcel H. <ke...@co...> - 2014-02-22 13:11:40
Attachments:
signature.asc
ssetester.tar.bz2
|
Hi Eric,
I have the feeling that you don't read my mails... I apologize, that I'm
not a native speaker but I think, that you can understand what I write.
I'd like to mention it once again.
***A stream is not something that you view in your browser!***
It's not a webpage, it's a stream of information that can be access and
evaluated by a javascript/cpp/perl/python/... programm.
There are two major problems in your approach.
1. You view the stream in your browser. That's not how it works. Please
adapt your 'showstatus.html' in line 14 to this:
> var stream = new EventSource('/robot/showstatus');
and replace the showStatus method with this
> void MyApp::showStatus()
> {
> stream_->accept(release_context());
> }
Then you can access it via:
> http://localhost:8080/showstatus.html
and see the promised result. I also attached the 'corrected' version.
I think, that your problem is, that you want both - stream and page - in
on method, but that won't work. You must have a synchronous app that
will deliver the page content [0] and a asynchronous app that will
deliver the data via sse.
The static content will be delivered via the internal file server of
cppcms in this way, but you should not rely on that in a productive
environment [1].
So. You need one application for the sse part and another application
for the webpage part.
The second major problem in your current version is, that you cannot
open that (wrong) page twice. Try to open another tab and view that page
again. It won't work. The can and should read the reason why [2][3].
So I hope that you won't be angry. Read the given pages and then I hope
you can answer your questions that you have. Of course, feel free to ask
more questions.
Greetings,
Marcel
[0] http://cppcms.com/wikipp/en/page/cppcms_1x_tut_hello
[1] http://cppcms.com/wikipp/en/page/cppcms_1x_serving_static_files
[2] http://cppcms.com/wikipp/en/page/cppcms_1x_application_lifetime
[3] http://cppcms.com/wikipp/en/page/cppcms_1x_event_loop
|
|
From: eric m. <mid...@gm...> - 2014-02-22 16:48:03
|
Hi Marcel,
I did read your emails thoroughly, although missed the link to the
applications_pool pages, as I thought you meant some piece of code by [0]
at first. I do understand that static ticker example. That is not the
problem, anymore.
What I indeed want is what you mentioned in your last response: I want the
streamed data to be displayed on a webpage that is not produced statically
(from the filesytem) but dynamically. I assumed that that could be done
from the same application but apparently that is not the case. You mention
multiple applications. Could it be as simple as registering both an
asynchronous application and a synchronous application in main() like this
or is that not possible at all?
cppcms::service service(argc, argv);
booster::intrusive_ptr<AsyncApp> asyncServer = new
AsyncApp(service);
service.applications_pool().mount(asyncServer);
service.applications_pool().mount(cppcms::applications_factory<SyncApp>());
service.run();
In the AsyncApp class I have implemented the ticker example and in the
SynApp class a variant of the tut_url_mapping example.
The constructor of AsynApp has mapper().root("/ticker"); and that of
SyncApp has mapper().root("/robot");
The config file is as follows:
{
"service" : {
"api" : "http",
"port" : 8080
},
"http" : {
"script_names" : [ "/robot", "/ticker" ]
},
"file_server" : {
"enable" : true,
"document_root" : "."
},
}
I added a method virtual string report() to cppcms::application that is
called every time application::main() is called and reports which
application calls it.
If I only mount the SyncApp and access the page by
127.0.0.1:8080/robot/showstatus than showstatus.html is displayed and the
following output follows on the console:
Sync::Sync() called
SyncApp->CppCMS::application::main(/showstatus) called
SyncApp::showStatus() called
SyncApp->CppCMS::application::main() called
If I only mount the AsyncApp and access the stream via
127.0.0.1:8080/showstatus.html (with var stream = new
EventSource('/ticker');) then the showstatus.html is displayed and the
stream of tickers updates the page as expected. The following output
follows on the console:
Async::Async() called
AsyncApp::main called
If I mount both SyncApp and AsyncApp and access
127.0.0.1:8080/showstatus.html than the page is displayed but no streaming
data. The following output follows on the console:
Async::Async() called
Sync::Sync() called
SyncApp->CppCMS::application::main() called
SyncApp->CppCMS::application::main() called
Which means to me that SyncApp gets to handle the request and not AsyncApp.
If I mount both and access 127.0.0.1:8080/robot/showstatus that the page is
displayed but no streaming data. The output on the console is slightly
different but the result is the same:
Async::Async() called
Sync::Sync() called
SyncApp->CppCMS::application::main(/showstatus) called
SyncApp::showStatus() called
SyncApp->CppCMS::application::main() called
Here also SyncApp::main is called and not AsyncApp::main.
Can you explain why the SyncApp supersedes and how I can make the AsyncApp
react on the streamrequest? It must be possible to implement the ticker
example using a dynamically created page right because that's what I'm
after.
Anyone who has a clue, please react.
Kind regards,
Eric
If I don't mount the SyncApp it works exactly as the ticker example,
updating the static page with the streamed data. If I don't mount the
AsyncApp it works exactly as the tut_url_mapping example. I if mount both
and send the same page to the browser but now dynamically from SyncApp,
there is no streaming data, which I would have expected as the page is
exactly the same page and there is an asynchronous app registered that
proved to respond when the page was loaded statically. Any ideas?
The server will be approached by only a single user so multiuser aspects
are no issue here.
Greetz,
Eric
On Sat, Feb 22, 2014 at 2:11 PM, Marcel Hellwig <ke...@co...> wrote:
> Hi Eric,
>
> I have the feeling that you don't read my mails... I apologize, that I'm
> not a native speaker but I think, that you can understand what I write.
>
> I'd like to mention it once again.
>
> ***A stream is not something that you view in your browser!***
>
> It's not a webpage, it's a stream of information that can be access and
> evaluated by a javascript/cpp/perl/python/... programm.
> There are two major problems in your approach.
>
> 1. You view the stream in your browser. That's not how it works. Please
> adapt your 'showstatus.html' in line 14 to this:
>
> > var stream = new EventSource('/robot/showstatus');
>
> and replace the showStatus method with this
>
> > void MyApp::showStatus()
> > {
> > stream_->accept(release_context());
> > }
>
> Then you can access it via:
>
> > http://localhost:8080/showstatus.html
>
> and see the promised result. I also attached the 'corrected' version.
>
> I think, that your problem is, that you want both - stream and page - in
> on method, but that won't work. You must have a synchronous app that
> will deliver the page content [0] and a asynchronous app that will
> deliver the data via sse.
> The static content will be delivered via the internal file server of
> cppcms in this way, but you should not rely on that in a productive
> environment [1].
> So. You need one application for the sse part and another application
> for the webpage part.
>
>
> The second major problem in your current version is, that you cannot
> open that (wrong) page twice. Try to open another tab and view that page
> again. It won't work. The can and should read the reason why [2][3].
>
> So I hope that you won't be angry. Read the given pages and then I hope
> you can answer your questions that you have. Of course, feel free to ask
> more questions.
>
> Greetings,
> Marcel
>
>
> [0] http://cppcms.com/wikipp/en/page/cppcms_1x_tut_hello
> [1] http://cppcms.com/wikipp/en/page/cppcms_1x_serving_static_files
> [2] http://cppcms.com/wikipp/en/page/cppcms_1x_application_lifetime
> [3] http://cppcms.com/wikipp/en/page/cppcms_1x_event_loop
>
--
Groetjes,
Eric
http://www.lightandmagicphotography.nl
http://www.lightandmagicphotography.com
|
|
From: Marcel H. <ke...@co...> - 2014-02-23 19:41:49
Attachments:
signature.asc
|
> cppcms::service service(argc, argv); > booster::intrusive_ptr<AsyncApp> asyncServer = new > AsyncApp(service); > service.applications_pool().mount(asyncServer); > > service.applications_pool().mount(cppcms::applications_factory<SyncApp>()); > service.run(); > I think what's missing here is a mount_point [0]. When you provide one, you should be able to access both. It would be nice if somebody else would also mention something ;) Greetings, Marcel [0] http://cppcms.com/cppcms_ref/latest/classcppcms_1_1applications__pool.html |
|
From: Lucile Q. <luc...@sa...> - 2014-02-24 20:57:20
|
Le 2014-02-22 11:47, eric middelkoop a écrit : > Can you explain why the SyncApp supersedes and how I can make the > AsyncApp react on the streamrequest? It must be possible to implement > the ticker example using a dynamically created page right because > that's what I'm after. > > Anyone who has a clue, please react. > When you look at applications_pool::get(..) in applications_pool.cpp : you can see that a first iteration is performed on synchronious applications to find the application witch mount_point match HOST/SCRIPT_NAME/PATH_INFO then a second iteration is performed on asynchronious applications. The first application found is returned. As you use the default mount_point SCRIPT_NAME is not checked and SyncApp is returned instead of AsyncApp. You should use a mount point that checks SCRIPT_NAME, and passes PATH_INFO for dispatching, see [0] for more information. Greetings, Lucile [0] http://cppcms.com/cppcms_ref/latest/classcppcms_1_1mount__point.html |
|
From: eric m. <mid...@gm...> - 2014-02-24 21:25:03
|
Hi Lucile, thanks for your comment. I figured it out already myself yesterday and do have a working example now. I might upload if later this week for others to benefit from. Thanks again! On Mon, Feb 24, 2014 at 9:37 PM, Lucile Quirion < luc...@sa...> wrote: > > Le 2014-02-22 11:47, eric middelkoop a écrit : > > Can you explain why the SyncApp supersedes and how I can make the > > AsyncApp react on the streamrequest? It must be possible to implement > > the ticker example using a dynamically created page right because > > that's what I'm after. > > > > Anyone who has a clue, please react. > > > When you look at applications_pool::get(..) in applications_pool.cpp : > you can see that a first iteration is performed on synchronious > applications to find the application witch mount_point match > HOST/SCRIPT_NAME/PATH_INFO then a second iteration is performed on > asynchronious applications. The first application found is returned. > > As you use the default mount_point SCRIPT_NAME is not checked and > SyncApp is returned instead of AsyncApp. > > You should use a mount point that checks SCRIPT_NAME, and passes > PATH_INFO for dispatching, see [0] for more information. > > Greetings, > Lucile > > [0] http://cppcms.com/cppcms_ref/latest/classcppcms_1_1mount__point.html > > > ------------------------------------------------------------------------------ > Flow-based real-time traffic analytics software. Cisco certified tool. > Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer > Customize your own dashboards, set traffic alerts and generate reports. > Network behavioral analysis & security monitoring. All-in-one tool. > > http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk > _______________________________________________ > Cppcms-users mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppcms-users > -- Groetjes, Eric http://www.lightandmagicphotography.nl http://www.lightandmagicphotography.com On Mon, Feb 24, 2014 at 9:37 PM, Lucile Quirion < luc...@sa...> wrote: > > Le 2014-02-22 11:47, eric middelkoop a écrit : > > Can you explain why the SyncApp supersedes and how I can make the > > AsyncApp react on the streamrequest? It must be possible to implement > > the ticker example using a dynamically created page right because > > that's what I'm after. > > > > Anyone who has a clue, please react. > > > When you look at applications_pool::get(..) in applications_pool.cpp : > you can see that a first iteration is performed on synchronious > applications to find the application witch mount_point match > HOST/SCRIPT_NAME/PATH_INFO then a second iteration is performed on > asynchronious applications. The first application found is returned. > > As you use the default mount_point SCRIPT_NAME is not checked and > SyncApp is returned instead of AsyncApp. > > You should use a mount point that checks SCRIPT_NAME, and passes > PATH_INFO for dispatching, see [0] for more information. > > Greetings, > Lucile > > [0] http://cppcms.com/cppcms_ref/latest/classcppcms_1_1mount__point.html > > > ------------------------------------------------------------------------------ > Flow-based real-time traffic analytics software. Cisco certified tool. > Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer > Customize your own dashboards, set traffic alerts and generate reports. > Network behavioral analysis & security monitoring. All-in-one tool. > > http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk > _______________________________________________ > Cppcms-users mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppcms-users > -- Groetjes, Eric http://www.lightandmagicphotography.nl http://www.lightandmagicphotography.com |