Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > dc51c7d3f8a5588a609f484ef81504ee > files > 77

libfastcgipp-devel-1.1-2mdv2010.0.i586.rpm

/***************************************************************************
* Copyright (C) 2007 Eddie                                                 *
*                                                                          *
* This file is part of fastcgi++.                                          *
*                                                                          *
* fastcgi++ is free software: you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as  published   *
* by the Free Software Foundation, either version 3 of the License, or (at *
* your option) any later version.                                          *
*                                                                          *
* fastcgi++ is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    *
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public     *
* License for more details.                                                *
*                                                                          *
* You should have received a copy of the GNU Lesser General Public License *
* along with fastcgi++.  If not, see <http://www.gnu.org/licenses/>.       *
****************************************************************************/


#include <fstream>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <fastcgi++/request.hpp>
#include <fastcgi++/manager.hpp>

// In this example we are going to use boost::asio to handle our timers and callback.
// Unfortunately because fastcgi buffers the output before sending it to the client by
// default, we will only get to see the true effects of the timer if you put the following
// directive in your apache configuration: FastCgiConfig -flush
#include <cstring>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
boost::asio::io_service io;

// I like to have an independent error log file to keep track of exceptions while debugging.
// You might want a different filename. I just picked this because everything has access there.
void error_log(const char* msg)
{
	using namespace std;
	using namespace boost;
	static ofstream error;
	if(!error.is_open())
	{
		error.open("/tmp/errlog", ios_base::out | ios_base::app);
		error.imbue(locale(error.getloc(), new posix_time::time_facet()));
	}

	error << '[' << posix_time::second_clock::local_time() << "] " << msg << endl;
}

// Let's make our request handling class. It must do the following:
// 1) Be derived from Fastcgipp::Request
// 2) Define the virtual response() member function from Fastcgipp::Request()

// First things first let's decide on what kind of character set we will use. Let's just
// use good old ISO-8859-1 this time. No wide characters

class Timer: public Fastcgipp::Request<char>
{
public:
	Timer(): state(START) {}
private:
	// We need to define a state variable so we know where we are when response() is called a second time.
	enum State { START, FINISH } state;

	boost::scoped_ptr<boost::asio::deadline_timer> t;

	bool response()
	{
		switch(state)
		{
			case START:
			{
				// Let's make our header, note the charset=ISO-8859-1. Remember that HTTP headers
				// must be terminated with \r\n\r\n. NOT just \n\n.
				out << "Content-Type: text/html; charset=ISO-8859-1\r\n\r\n";

				// Here it's all stuff you should be familiar with
				out << "<html><head><meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1' />";
				out << "<title>fastcgi++: Threaded Timer</title></head><body>";
				
				// Output a message saying we are starting the timer
				out << "Starting Timer...<br />";

				// Let's flush the buffer just to get it out there.
				out.flush();

				// Make a five second timer
				t.reset(new boost::asio::deadline_timer(io, boost::posix_time::seconds(5)));

				// Now we work with our callback. Defined in the Fastcgipp::Request is a boost::function
				// that takes a Fastcgipp::Message (defined in fastcgi++/protocol.hpp) as a single argument.
				// This callback function will pass the message on to this request therebye calling the response()
				// function again. The callback function is thread safe. That means you can pass messages back to
				// requests from other threads.

				// Let's build the message we want sent back to here.
				Fastcgipp::Message msg;
				// The first part of the message we have to define is the type. A type of 0 means a fastcgi message
				// and is used internally. All other values we can use ourselves to define different message types (sql queries,
				// file grabs, etc...). We will use type=1 for timer stuff.
				msg.type=1;

				// Now let's put a character string into the message as well. Just for fun.
				{
					char cString[] = "I was passed between two threads!!";
					msg.size=sizeof(cString);
					msg.data.reset(new char[sizeof(cString)]);
					std::strncpy(msg.data.get(), cString, sizeof(cString));
				}

				// Now we will give our callback data to boost::asio
				t->async_wait(boost::bind(callback, msg));

				// We need to set our state to FINISH so that when this response is called a second time, we don't repeat this.
				state=FINISH;

				// Now we will return and allow the task manager to do other things (or sleep if there is nothing to do).
				// We must return false if the request is not yet complete.
				return false;
			}
			case FINISH:
			{
				// Although we don't need the message we were sent, it is stored in the Request class as member data named
				// "message".
				out << "Timer Finished! Our message data was \"" << message.data.get() << "\"";
				out << "</body></html>";

				// Always return true if you are done. This will let apache know we are done
				// and the manager will destroy the request and free it's resources.
				// Return false if you are not finished but want to relinquish control and
				// allow other requests to operate.
				return true;
			}
		}
	}
};

// The main function is easy to set up
int main()
{
	try
	{
		// Let's first setup a thread for our timers. We assign a work object
		// to it so that boost::asio::io_service::run does not return until
		// the work object goes out of scope.
		boost::asio::io_service::work w(io);
		boost::thread t(boost::bind(&boost::asio::io_service::run, &io));

		// Now we make a Fastcgipp::Manager object, with our request handling class
		// as a template parameter.
		Fastcgipp::Manager<Timer> fcgi;
		// Now just call the object handler function. It will sleep quietly when there
		// are no requests and efficiently manage them when there are many.
		fcgi.handler();
	}
	catch(std::exception& e)
	{
		error_log(e.what());
	}
}