diff options
| -rw-r--r-- | icespider/common/session.ice | 27 | ||||
| -rw-r--r-- | icespider/fileSessions/Jamfile.jam | 13 | ||||
| -rw-r--r-- | icespider/fileSessions/fileSessions.cpp | 132 | ||||
| -rw-r--r-- | icespider/unittests/Jamfile.jam | 14 | ||||
| -rw-r--r-- | icespider/unittests/testFileSessions.cpp | 112 | 
5 files changed, 298 insertions, 0 deletions
diff --git a/icespider/common/session.ice b/icespider/common/session.ice new file mode 100644 index 0000000..4947f9f --- /dev/null +++ b/icespider/common/session.ice @@ -0,0 +1,27 @@ +#ifndef ICESPIDER_SESSION_ICE +#define ICESPIDER_SESSION_ICE + +module IceSpider { +	dictionary<string, string> Variables; + +	exception SessionError { +		string what; +	}; + +	class Session { +		string id; +		long lastUsed; +		short duration; +		Variables variables; +	}; + +	interface SessionManager { +		Session createSession() throws SessionError; +		Session getSession(string id) throws SessionError; +		void updateSession(Session session) throws SessionError; +		void destroySession(string id) throws SessionError; +	}; +}; + +#endif + diff --git a/icespider/fileSessions/Jamfile.jam b/icespider/fileSessions/Jamfile.jam new file mode 100644 index 0000000..f08559d --- /dev/null +++ b/icespider/fileSessions/Jamfile.jam @@ -0,0 +1,13 @@ +lib adhocutil : : : : <include>/usr/include/adhocutil ; +lib boost_system ; +lib boost_filesystem ; + +lib icespider-filesessions : +	[ glob *.cpp ] +	: +	<library>boost_system +	<library>boost_filesystem +	<library>adhocutil +	<library>../core//icespider-core +	; + diff --git a/icespider/fileSessions/fileSessions.cpp b/icespider/fileSessions/fileSessions.cpp new file mode 100644 index 0000000..d2d5823 --- /dev/null +++ b/icespider/fileSessions/fileSessions.cpp @@ -0,0 +1,132 @@ +#include <core.h> +#include <session.h> +#include <fcntl.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <factory.impl.h> +#include <boost/filesystem/operations.hpp> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/uuid/uuid_io.hpp> +#include <Ice/Stream.h> +#include "Ice/Initialize.h" + +namespace IceSpider { +	class FileSessions : public Plugin, public SessionManager { +		public: +			FileSessions(Ice::CommunicatorPtr c, Ice::PropertiesPtr p) : +				ic(c), +				root(p->getProperty("IceSpider.FileSessions.Path")), +				duration(p->getPropertyAsIntWithDefault("IceSpider.FileSessions.Duration", 3600)) +			{ +				if (!root.empty()) +					if (!boost::filesystem::exists(root)) +						boost::filesystem::create_directories(root); +			} + +			~FileSessions() +			{ +				removeExpired(); +			} + +			SessionPtr createSession(const ::Ice::Current &) override +			{ +				SessionPtr s = new Session(); +				s->id = boost::lexical_cast<std::string>(boost::uuids::random_generator()()); +				s->duration = duration; +				save(s); +				return s; +			} + +			SessionPtr getSession(const ::std::string & id, const ::Ice::Current & current) override +			{ +				auto s = load(id); +				if (s && isExpired(s)) { +					destroySession(id, current); +					return NULL; +				} +				return s; +			} + +			void updateSession(const SessionPtr & s, const ::Ice::Current &) override +			{ +				save(s); +			} + +			void destroySession(const ::std::string & id, const ::Ice::Current &) override +			{ +				try { +					boost::filesystem::remove(root / id); +				} +				catch (const std::exception & e) { +					throw SessionError(e.what()); +				} +			} + +		private: +			void save(SessionPtr s) +			{ +				time(&s->lastUsed); +				auto buf = Ice::createOutputStream(ic); +				buf->write(s); +				auto range = buf->finished(); +				auto fd = sysassert(open((root / s->id).c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR), -1); +				sysassert(flock(fd, LOCK_EX), -1); +				sysassert(pwrite(fd, range.first, range.second - range.first, 0), -1); +				sysassert(ftruncate(fd, range.second - range.first), -1); +				sysassert(flock(fd, LOCK_UN), -1); +				sysassert(close(fd), -1); +			} + +			SessionPtr load(const std::string & id) +			{ +				int fd = open((root / id).c_str(), O_RDONLY); +				if (fd == -1 && errno == ENOENT) return NULL; +				sysassert(fd, -1); +				sysassert(flock(fd, LOCK_SH), -1); +				struct stat st; +				sysassert(fstat(fd, &st), -1); +				auto fbuf = sysassert((Ice::Byte *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0), (Ice::Byte *)NULL); +				auto buf = Ice::createInputStream(ic, std::make_pair(fbuf, fbuf + st.st_size)); +				SessionPtr s; +				buf->read(s); +				sysassert(flock(fd, LOCK_UN), -1); +				sysassert(close(fd), -1); +				return s; +			} + +			void removeExpired() +			{ +				if (root.empty() || !boost::filesystem::exists(root)) return; +				boost::filesystem::directory_iterator di(root); +				while (di != boost::filesystem::directory_iterator()) { +					auto s = load(di->path().leaf().string()); +					if (s && isExpired(s)) { +						destroySession(s->id, Ice::Current()); +					} +					di++; +				} +			} + +			bool isExpired(SessionPtr s) +			{ +				return (s->lastUsed + s->duration < time(NULL)); +			} + +			template<typename R, typename ER> +			R sysassert(R rtn, ER ertn) +			{ +				if (rtn == ertn) { +					fprintf(stderr, "%s\n", strerror(errno)); +					throw SessionError(strerror(errno)); +				} +				return rtn; +			} + +			Ice::CommunicatorPtr ic; + 			const boost::filesystem::path root; +			const Ice::Int duration; +	}; +} +NAMEDFACTORY("IceSpider-FileSessions", IceSpider::FileSessions, IceSpider::PluginFactory); + diff --git a/icespider/unittests/Jamfile.jam b/icespider/unittests/Jamfile.jam index 4ee2bd8..ba7e9c2 100644 --- a/icespider/unittests/Jamfile.jam +++ b/icespider/unittests/Jamfile.jam @@ -100,6 +100,20 @@ run  	<include>../fcgi  	: testFcgi ; +run +	testFileSessions.cpp +	: : +	config/ice.properties +	: +	<define>BOOST_TEST_DYN_LINK +	<library>../fileSessions//icespider-filesessions +	<library>../common//icespider-common +	<library>testCommon +	<library>boost_system +	<library>boost_filesystem +	<library>../core//icespider-core +	; +  lib test-api :  	test-api.ice  	: diff --git a/icespider/unittests/testFileSessions.cpp b/icespider/unittests/testFileSessions.cpp new file mode 100644 index 0000000..37e6587 --- /dev/null +++ b/icespider/unittests/testFileSessions.cpp @@ -0,0 +1,112 @@ +#define BOOST_TEST_MODULE TestFileSessions +#include <boost/test/unit_test.hpp> + +#include <Ice/Initialize.h> +#include <Ice/Properties.h> +#include <session.h> +#include <core.h> +#include <definedDirs.h> + +BOOST_TEST_DONT_PRINT_LOG_VALUE(IceSpider::StringMap); + +class TestCore : public IceSpider::Core { +	public: +		TestCore() : +			IceSpider::Core({ +				"--IceSpider.SessionManager=IceSpider-FileSessions", +				"--IceSpider.FileSessions.Path=" + (binDir / "test-sessions").string(), +				"--IceSpider.FileSessions.Duration=0" +			}), +			root(communicator->getProperties()->getProperty("IceSpider.FileSessions.Path")) +		{ +		} +		const boost::filesystem::path root; +}; + +BOOST_AUTO_TEST_CASE( clear ) +{ +	TestCore tc; +	if (boost::filesystem::exists(tc.root)) { +		boost::filesystem::remove_all(tc.root); +	} +} + +BOOST_FIXTURE_TEST_SUITE(Core, TestCore); + +BOOST_AUTO_TEST_CASE( ping ) +{ +	auto prx = this->getProxy<IceSpider::SessionManager>(); +	BOOST_REQUIRE(prx); +	prx->ice_ping(); +} + +BOOST_AUTO_TEST_CASE( createAndDestroy ) +{ +	auto prx = this->getProxy<IceSpider::SessionManager>(); +	auto s = prx->createSession(); +	BOOST_REQUIRE(boost::filesystem::exists(root / s->id)); +	BOOST_REQUIRE_EQUAL(0, s->duration); +	BOOST_REQUIRE_EQUAL(time(NULL), s->lastUsed); +	prx->destroySession(s->id); +	BOOST_REQUIRE(!boost::filesystem::exists(root / s->id)); +} + +BOOST_AUTO_TEST_CASE( createAndChangeRestore ) +{ +	auto prx = this->getProxy<IceSpider::SessionManager>(); +	auto s = prx->createSession(); +	s->variables["a"] = "value"; +	prx->updateSession(s); + +	auto s2 = prx->getSession(s->id); +	BOOST_REQUIRE_EQUAL(s->id, s2->id); +	BOOST_REQUIRE_EQUAL(s->variables, s2->variables); + +	prx->destroySession(s->id); +} + +BOOST_AUTO_TEST_CASE( createAndExpire ) +{ +	auto prx = this->getProxy<IceSpider::SessionManager>(); +	auto s = prx->createSession(); +	BOOST_REQUIRE(boost::filesystem::exists(root / s->id)); +	BOOST_REQUIRE_EQUAL(0, s->duration); +	BOOST_REQUIRE_EQUAL(time(NULL), s->lastUsed); +	usleep(1001000); +	BOOST_REQUIRE(boost::filesystem::exists(root / s->id)); +	BOOST_REQUIRE(!prx->getSession(s->id)); +	BOOST_REQUIRE(!boost::filesystem::exists(root / s->id)); +} + +BOOST_AUTO_TEST_CASE( missing ) +{ +	auto prx = this->getProxy<IceSpider::SessionManager>(); +	BOOST_REQUIRE(!prx->getSession("missing")); +	BOOST_REQUIRE(!boost::filesystem::exists(root / "missing")); +} + +BOOST_AUTO_TEST_CASE( createAndLeave ) +{ +	auto prx = this->getProxy<IceSpider::SessionManager>(); +	auto s = prx->createSession(); +	BOOST_REQUIRE(boost::filesystem::exists(root / s->id)); +} + +BOOST_AUTO_TEST_CASE( left ) +{ +	BOOST_REQUIRE(!boost::filesystem::is_empty(root)); +} + +BOOST_AUTO_TEST_CASE( expire ) +{ +	usleep(1001000); +} + +BOOST_AUTO_TEST_SUITE_END(); + +BOOST_AUTO_TEST_CASE( empty ) +{ +	TestCore tc; +	BOOST_REQUIRE(boost::filesystem::is_empty(tc.root)); +} +  | 
