diff options
49 files changed, 968 insertions, 300 deletions
diff --git a/p2pvr/daemon/Jamfile.jam b/p2pvr/daemon/Jamfile.jam index ac3ed58..d9894d3 100644 --- a/p2pvr/daemon/Jamfile.jam +++ b/p2pvr/daemon/Jamfile.jam @@ -11,7 +11,7 @@ cpp-pch pch : pch.hpp :  lib p2pvrdaemon :  	pch -	[ glob-tree *.cpp *.sql : dummy* test*.cpp ] +	[ glob-tree *.cpp *.sql : dummy* test*.cpp mock*.cpp ]  	:  	<library>../ice//p2pvrice  	<library>../lib//p2pvrlib diff --git a/p2pvr/daemon/events.cpp b/p2pvr/daemon/events.cpp new file mode 100644 index 0000000..676b2b3 --- /dev/null +++ b/p2pvr/daemon/events.cpp @@ -0,0 +1,101 @@ +#include <pch.hpp> +#include "containerCreator.h" +#include <p2pvr.h> +#include <p2Helpers.h> + +template<> +void +CreateColumns<P2PVR::EventPtr>(const ColumnCreator & cc) +{ +	cc("eventUid", false); +	cc("serviceId", true); +	cc("eventId", true); +	cc("title", false); +	cc("titleLang", false); +	cc("subtitle", false); +	cc("description", false); +	cc("descriptionLang", false); +	cc("videoAspect", false); +	cc("videoFrameRate", false); +	cc("videoHd", false); +	cc("audioChannels", false); +	cc("audioLanguage", false); +	cc("subtitleLanguage", false); +	cc("category", false); +	cc("subCategory", false); +	cc("userCategory", false); +	cc("dvbRating", false); +	cc("startTime", false); +	cc("stopTime", false); +	cc("episode", false); +	cc("episodes", false); +	cc("year", false); +	cc("flags", false); +	cc("season", false); +	cc("current", false); +} + +template<> +void +BindColumns(RowState & rs, const P2PVR::EventPtr & e) +{ +	rs.fields[0] << e->ServiceId; +	rs.fields[1] << e->EventId; +	rs.fields[2] << e->Title; +	rs.fields[3] << e->TitleLang; +	rs.fields[4] << e->Subtitle; +	rs.fields[5] << e->Description; +	rs.fields[6] << e->DescriptionLang; +	rs.fields[7] << e->VideoAspect; +	rs.fields[8] << e->VideoFrameRate; +	rs.fields[9] << e->VideoHD; +	rs.fields[10] << e->AudioChannels; +	rs.fields[11] << e->AudioLanguage; +	rs.fields[12] << e->SubtitleLanguage; +	rs.fields[13] << e->Category; +	rs.fields[14] << e->SubCategory; +	rs.fields[15] << e->UserCategory; +	rs.fields[16] << e->DvbRating; +	rs.fields[17] << e->StartTime; +	rs.fields[18] << e->StopTime; +	rs.fields[19] << e->Episode; +	rs.fields[20] << e->Episodes; +	rs.fields[21] << e->Year; +	rs.fields[22] << e->Flags; +	rs.fields[23] << e->Season; +	rs.fields[24] << e->EventUid; +	rs.fields[25] << e->Current; +} + +template<> +void +UnbindColumns(RowState & rs, const P2PVR::EventPtr & e) +{ +	rs.fields[0] >> e->ServiceId; +	rs.fields[1] >> e->EventId; +	rs.fields[2] >> e->Title; +	rs.fields[3] >> e->TitleLang; +	rs.fields[4] >> e->Subtitle; +	rs.fields[5] >> e->Description; +	rs.fields[6] >> e->DescriptionLang; +	rs.fields[7] >> e->VideoAspect; +	rs.fields[8] >> e->VideoFrameRate; +	rs.fields[9] >> e->VideoHD; +	rs.fields[10] >> e->AudioChannels; +	rs.fields[11] >> e->AudioLanguage; +	rs.fields[12] >> e->SubtitleLanguage; +	rs.fields[13] >> e->Category; +	rs.fields[14] >> e->SubCategory; +	rs.fields[15] >> e->UserCategory; +	rs.fields[16] >> e->DvbRating; +	rs.fields[17] >> e->StartTime; +	rs.fields[18] >> e->StopTime; +	rs.fields[19] >> e->Episode; +	rs.fields[20] >> e->Episodes; +	rs.fields[21] >> e->Year; +	rs.fields[22] >> e->Flags; +	rs.fields[23] >> e->Season; +	rs.fields[24] >> e->EventUid; +	rs.fields[25] >> e->Current; +} + diff --git a/p2pvr/daemon/maintenance/events.cpp b/p2pvr/daemon/maintenance/events.cpp index 648be0b..f075a32 100644 --- a/p2pvr/daemon/maintenance/events.cpp +++ b/p2pvr/daemon/maintenance/events.cpp @@ -9,6 +9,9 @@  #include <singleIterator.h>  #include <temporaryIceAdapterObject.h>  #include <commonHelpers.h> +#include <resources.h> + +ResourceString(Maint_pruneEvents, sql_Maint_pruneEvents);  class SiEventsHandler : public SiEpgParser {  	public: @@ -81,8 +84,11 @@ Maintenance::UpdateEvents(short type, const Ice::Current & ice)  	SqlMergeTask mergeEvents("postgres", "events");  	CreateColumns<DVBSI::EventPtr>(boost::bind(SqlMergeColumnsInserter, &mergeEvents, _1, _2));  	mergeEvents.sources.insert(new SiEventsMerger(type, ice)); +	mergeEvents.insteadOfDelete = new DynamicSql::SqlText("SET current = false"); +	mergeEvents.updateWhere = new DynamicSql::SqlText("a.current");  	mergeEvents.loadComplete(this);  	mergeEvents.execute(NULL); +	Modify(Maint_pruneEvents).second->execute();  	tx.Commit();  	Logger()->messagebf(LOG_INFO, "%s: Updated events", __PRETTY_FUNCTION__); diff --git a/p2pvr/daemon/recorder.cpp b/p2pvr/daemon/recorder.cpp index 6cd0b5f..35aeba8 100644 --- a/p2pvr/daemon/recorder.cpp +++ b/p2pvr/daemon/recorder.cpp @@ -39,13 +39,13 @@ Recorder::RefreshSchedules(const Ice::Current &)  	auto si = P2PVR::SIPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("SI")));  	BOOST_FOREACH(const auto & s, schedules->GetScheduledToRecord()) {  		if (std::find_if(currentRecordings.begin(), currentRecordings.end(), [&s](const CurrentPtr & c) { -					return s->ScheduleId == c->schedule->ScheduleId && s->ServiceId == c->event->ServiceId && s->EventId == c->event->EventId;; +					return s->ScheduleId == c->schedule->ScheduleId && s->EventUid == c->event->EventUid;  				}) != currentRecordings.end()) {  			continue;  		}  		auto schedule = schedules->GetSchedule(s->ScheduleId); -		auto service = si->GetService(s->ServiceId); -		auto event = si->GetEvent(s->ServiceId, s->EventId); +		auto event = si->GetEvents({ s->EventUid }).front(); +		auto service = si->GetService(event->ServiceId);  		auto startIn = std::max<time_t>((*event->StartTime - *schedule->Early - boost::posix_time::second_clock::universal_time()).total_seconds(), 0);  		IceUtil::TimerTaskPtr startTimer = new BindTimerTask(boost::bind(&Recorder::StartRecording, this, schedule, service, event)); @@ -56,7 +56,7 @@ Recorder::RefreshSchedules(const Ice::Current &)  }  void -Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event) +Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, P2PVR::EventPtr event)  {  	std::lock_guard<std::mutex> g(lock);  	auto storage = P2PVR::StoragePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Storage"))); @@ -79,8 +79,7 @@ Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service,  			event->Title, event->StartTime, event->StopTime,  			service->Name ? *service->Name : "<no name>", service->ServiceId); -	recordings->NewRecording(new P2PVR::Recording(0, storage->ice_toString(), id, schedule->ScheduleId, event->Title, event->Subtitle, -				event->Description, event->StartTime, *(*event->StopTime - *event->StartTime))); +	recordings->NewRecording(new P2PVR::Recording(0, storage->ice_toString(), id, schedule->ScheduleId, event->EventUid));  	auto newCurrent = CurrentPtr(new Current({muxer, store, ss, schedule, service, event, IceUtil::TimerTaskPtr()}));  	currentRecordings.insert(newCurrent); diff --git a/p2pvr/daemon/recorder.h b/p2pvr/daemon/recorder.h index 78c604b..6680801 100644 --- a/p2pvr/daemon/recorder.h +++ b/p2pvr/daemon/recorder.h @@ -19,7 +19,7 @@ class Recorder : public P2PVR::Recorder {  				ServiceStreamerPtr stream;  				P2PVR::SchedulePtr schedule;  				DVBSI::ServicePtr service; -				DVBSI::EventPtr event; +				P2PVR::EventPtr event;  				IceUtil::TimerTaskPtr stopTimer;  		};  		typedef boost::shared_ptr<Current> CurrentPtr; @@ -33,7 +33,7 @@ class Recorder : public P2PVR::Recorder {  	private:  		void StartRecordings(); -		void StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event); +		void StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, P2PVR::EventPtr event);  		void StopRecording(CurrentPtr);  		Ice::ObjectAdapterPtr adapter; diff --git a/p2pvr/daemon/recordings.cpp b/p2pvr/daemon/recordings.cpp index 73cf77d..ceb89ba 100644 --- a/p2pvr/daemon/recordings.cpp +++ b/p2pvr/daemon/recordings.cpp @@ -19,11 +19,7 @@ CreateColumns<P2PVR::RecordingPtr>(const ColumnCreator & cc)  	cc("storageaddress", false);  	cc("guid", false);  	cc("scheduleid", false); -	cc("title", false); -	cc("subtitle", false); -	cc("description", false); -	cc("starttime", false); -	cc("duration", false); +	cc("eventuid", false);  }  template<> @@ -34,11 +30,7 @@ UnbindColumns(RowState & rs, const P2PVR::RecordingPtr & r)  	rs.fields[1] >> r->StorageAddress;  	rs.fields[2] >> r->Guid;  	rs.fields[3] >> r->ScheduleId; -	rs.fields[4] >> r->Title; -	rs.fields[5] >> r->Subtitle; -	rs.fields[6] >> r->Description; -	rs.fields[7] >> r->StartTime; -	rs.fields[8] >> r->Duration; +	rs.fields[4] >> r->EventUid;  }  int @@ -46,8 +38,7 @@ Recordings::NewRecording(const P2PVR::RecordingPtr & r, const Ice::Current &)  {  	Logger()->messagebf(LOG_INFO, "%s: Creating new recording %s at %s", __PRETTY_FUNCTION__, r->Guid, r->StorageAddress);  	TxHelper tx(this); -	auto insert = Modify(Recording_Insert, -			r->StorageAddress, r->Guid, r->ScheduleId, r->Title, r->Subtitle, r->Description, r->StartTime, r->Duration); +	auto insert = Modify(Recording_Insert, r->StorageAddress, r->Guid, r->ScheduleId, r->EventUid);  	insert.second->execute();  	r->RecordingId = SelectScalar<int>(Recording_InsertNewId);  	Logger()->messagebf(LOG_INFO, "%s: Created recording Id: %d", __PRETTY_FUNCTION__, r->RecordingId); @@ -65,8 +56,10 @@ Recordings::DeleteRecording(int id, const Ice::Current & ice)  		std::string addr = recordingStorages.second / "storageaddress";  		std::string guid = recordingStorages.second / "guid";  		auto storage = P2PVR::StoragePrx::checkedCast(ic->stringToProxy(addr)); -		storage->Delete(guid); -		Logger()->messagebf(LOG_DEBUG, "%s: Delete %s from StorageAddress %s", __PRETTY_FUNCTION__, guid, addr); +		if (storage) { +			storage->Delete(guid); +			Logger()->messagebf(LOG_DEBUG, "%s: Delete %s from StorageAddress %s", __PRETTY_FUNCTION__, guid, addr); +		}  	}  	Modify(Recording_Delete, id).second->execute();  } diff --git a/p2pvr/daemon/schedules.cpp b/p2pvr/daemon/schedules.cpp index dab3917..b97924d 100644 --- a/p2pvr/daemon/schedules.cpp +++ b/p2pvr/daemon/schedules.cpp @@ -31,8 +31,7 @@ END_OPTIONS()  class ScheduleCandidate {  	public:  		std::string What; -		int ServiceId; -		int EventId; +		int EventUid;  		int TransportStreamId;  		datetime StartTime;  		datetime StopTime; @@ -51,16 +50,14 @@ enum RecordStatuses {  class Record {  	public:  		Record() { }; -		Record(int s, int e, RecordStatuses rs, int sc) : -			ServiceId(s), -			EventId(e), +		Record(int e, RecordStatuses rs, int sc) : +			EventUid(e),  			RecordStatus(rs),  			ScheduleId(sc)  		{  		} -		int ServiceId; -		int EventId; +		int EventUid;  		RecordStatuses RecordStatus;  		int ScheduleId;  }; @@ -71,8 +68,7 @@ template<>  void  CreateColumns<P2PVR::ScheduledToRecordPtr>(const ColumnCreator & cc)  { -	cc("serviceid", true); -	cc("eventid", true); +	cc("eventuid", true);  	cc("scheduleid", true);  } @@ -80,9 +76,8 @@ template<>  void  UnbindColumns(RowState & rs, P2PVR::ScheduledToRecordPtr const & s)  { -	rs.fields[0] >> s->ServiceId; -	rs.fields[1] >> s->EventId; -	rs.fields[2] >> s->ScheduleId; +	rs.fields[0] >> s->EventUid; +	rs.fields[1] >> s->ScheduleId;  }  template<> @@ -91,7 +86,7 @@ CreateColumns<ScheduleCandidatePtr>(const ColumnCreator & cc)  {  	cc("what", true);  	cc("serviceid", false); -	cc("eventid", false); +	cc("eventuid", false);  	cc("transportstreamid", false);  	cc("starttime", false);  	cc("stoptime", false); @@ -104,13 +99,12 @@ void  UnbindColumns(RowState & rs, ScheduleCandidatePtr const & s)  {  	rs.fields[0] >> s->What; -	rs.fields[1] >> s->ServiceId; -	rs.fields[2] >> s->EventId; -	rs.fields[3] >> s->TransportStreamId; -	rs.fields[4] >> s->StartTime; -	rs.fields[5] >> s->StopTime; -	rs.fields[6] >> s->Priority; -	rs.fields[7] >> s->ScheduleId; +	rs.fields[1] >> s->EventUid; +	rs.fields[2] >> s->TransportStreamId; +	rs.fields[3] >> s->StartTime; +	rs.fields[4] >> s->StopTime; +	rs.fields[5] >> s->Priority; +	rs.fields[6] >> s->ScheduleId;  }  template<> @@ -119,7 +113,7 @@ CreateColumns<P2PVR::SchedulePtr>(const ColumnCreator & cc)  {  	cc("scheduleid", true);  	cc("serviceid", false); -	cc("eventid", false); +	cc("eventuid", false);  	cc("title", false);  	cc("search", false);  	cc("priority", false); @@ -134,7 +128,7 @@ UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s)  {  	rs.fields[0] >> s->ScheduleId;  	rs.fields[1] >> s->ServiceId; -	rs.fields[2] >> s->EventId; +	rs.fields[2] >> s->EventUid;  	rs.fields[3] >> s->Title;  	rs.fields[4] >> s->Search;  	rs.fields[5] >> s->Priority; @@ -147,8 +141,7 @@ template<>  void  CreateColumns<RecordPtr>(const ColumnCreator & cc)  { -	cc("serviceid", true); -	cc("eventid", true); +	cc("eventuid", true);  	cc("recordstatus", false);  	cc("scheduleid", false);  } @@ -157,16 +150,14 @@ template<>  void  BindColumns(RowState & rs, RecordPtr const & s)  { -	rs.fields[0] << s->ServiceId; -	rs.fields[1] << s->EventId; -	rs.fields[2] << (int)s->RecordStatus; -	rs.fields[3] << s->ScheduleId; +	rs.fields[0] << s->EventUid; +	rs.fields[1] << (int)s->RecordStatus; +	rs.fields[2] << s->ScheduleId;  } -Showing::Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep) : +Showing::Showing(unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep) :  	episode(ep), -	serviceId(s), -	eventId(e), +	eventUid(e),  	priority(p),  	scheduleId(sc),  	transportStreamId(t), @@ -338,7 +329,7 @@ Schedules::DoReschedule(const Ice::Current & ice)  			cur = new Episode(c->What);  			scheduleList.push_back(cur);  		} -		ShowingPtr s = new Showing(c->ServiceId, c->EventId, c->TransportStreamId, c->ScheduleId, +		ShowingPtr s = new Showing(c->EventUid, c->TransportStreamId, c->ScheduleId,  				c->StartTime, c->StopTime, c->Priority, cur.get());  		minPriority = std::min(minPriority, s->priority);  		cur->showings.push_back(s); @@ -408,7 +399,7 @@ Schedules::DoReschedule(const Ice::Current & ice)  			}  			BOOST_FOREACH(const auto & i, c->showings) {  				if (i) { -					records.push_back(RecordPtr(new Record(i->serviceId, i->eventId, +					records.push_back(RecordPtr(new Record(i->eventUid,  									found ?  									selected.find(i) != selected.end() ? Record_WillRecordThisShowing : Record_WillRecordOtherShowing :  									Record_CannotRecordAnyShowing, i->scheduleId))); @@ -470,11 +461,11 @@ Schedules::UpdateSchedule(const P2PVR::SchedulePtr & s, const Ice::Current & ice  {  	TxHelper tx(this);  	if (s->ScheduleId == 0) { -		Modify(Schedules_insert, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats).second->execute(); +		Modify(Schedules_insert, s->ServiceId, s->EventUid, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats).second->execute();  		s->ScheduleId = SelectScalar<int>(Schedules_insertNewId);  	}  	else { -		Modify(Schedules_update, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats, s->ScheduleId).second->execute(); +		Modify(Schedules_update, s->ServiceId, s->EventUid, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats, s->ScheduleId).second->execute();  	}  	DoReschedule(ice);  	return s->ScheduleId; diff --git a/p2pvr/daemon/schedules.h b/p2pvr/daemon/schedules.h index f7075dd..2ff9e0f 100644 --- a/p2pvr/daemon/schedules.h +++ b/p2pvr/daemon/schedules.h @@ -11,11 +11,10 @@ class Episode;  class Showing : public IntrusivePtrBase {  	public: -		Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep); +		Showing(unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep);  		// Record what?  		const Episode * episode; -		const unsigned int serviceId; -		const unsigned int eventId; +		const unsigned int eventUid;  		int priority;  		const unsigned int scheduleId;  		// Requires diff --git a/p2pvr/daemon/si.cpp b/p2pvr/daemon/si.cpp index 571c6b0..0c5162e 100644 --- a/p2pvr/daemon/si.cpp +++ b/p2pvr/daemon/si.cpp @@ -9,6 +9,7 @@  ResourceString(SI_serviceNextUsed, sql_SI_serviceNextUsed);  ResourceString(SI_servicesSelectAll, sql_SI_servicesSelectAll);  ResourceString(SI_servicesSelectById, sql_SI_servicesSelectById); +ResourceString(SI_eventByUid, sql_SI_eventByUid);  ResourceString(SI_eventById, sql_SI_eventById);  ResourceString(SI_eventsOnNow, sql_SI_eventsOnNow);  ResourceString(SI_eventsInSchedule, sql_SI_eventsInSchedule); @@ -100,57 +101,69 @@ SI::GetService(int id, const Ice::Current&)  	return rtn.front();  } -DVBSI::EventPtr +P2PVR::Events +SI::GetEvents(const P2PVR::IntSequence & eventUids, const Ice::Current &) +{ +	P2PVR::Events rtn; +	SqlContainerCreator<P2PVR::Events, P2PVR::Event> cc(rtn); +	BOOST_FOREACH(const auto & uid, eventUids){ +		cc.populate(Select(SI_eventByUid, uid).second); +	} +	if (rtn.size() != eventUids.size()) throw P2PVR::NotFound(); +	return rtn; +} + +P2PVR::EventPtr  SI::GetEvent(int serviceId, int eventId, const Ice::Current &)  { -	DVBSI::Events rtn; -	SqlContainerCreator<DVBSI::Events, DVBSI::Event> cc(rtn); +	P2PVR::Events rtn; +	SqlContainerCreator<P2PVR::Events, P2PVR::Event> cc(rtn);  	cc.populate(Select(SI_eventById, serviceId, eventId).second);  	if (rtn.empty()) throw P2PVR::NotFound();  	return rtn.front();  } -DVBSI::Events +P2PVR::Events  SI::EventsOnNow(const Ice::Current &)  { -	DVBSI::Events rtn; -	SqlContainerCreator<DVBSI::Events, DVBSI::Event> cc(rtn); +	P2PVR::Events rtn; +	SqlContainerCreator<P2PVR::Events, P2PVR::Event> cc(rtn);  	cc.populate(Select(SI_eventsOnNow).second);  	return rtn;  } -DVBSI::Events +P2PVR::Events  SI::EventsInRange(const Common::DateTime & from, const Common::DateTime & to, const Ice::Current &)  { -	DVBSI::Events rtn; -	SqlContainerCreator<DVBSI::Events, DVBSI::Event> cc(rtn); +	P2PVR::Events rtn; +	SqlContainerCreator<P2PVR::Events, P2PVR::Event> cc(rtn);  	cc.populate(Select(SI_eventsInRange, from, to).second);  	return rtn;  } -DVBSI::Events +P2PVR::Events  SI::EventSearch(const IceUtil::Optional<std::string> & keywords, const IceUtil::Optional<Ice::Int> & serviceId, const IceUtil::Optional<Common::DateTime> & from, const IceUtil::Optional<Common::DateTime> & to, const Ice::Current &)  { -	DVBSI::Events rtn; -	SqlContainerCreator<DVBSI::Events, DVBSI::Event> cc(rtn); +	P2PVR::Events rtn; +	SqlContainerCreator<P2PVR::Events, P2PVR::Event> cc(rtn);  	cc.populate(Select(SI_eventSearch, from, to, serviceId, serviceId, keywords, keywords, keywords, keywords).second);  	return rtn;  } -DVBSI::Events +P2PVR::Events  SI::EventsInSchedules(const Ice::Current &)  { -	DVBSI::Events rtn; -	SqlContainerCreator<DVBSI::Events, DVBSI::Event> cc(rtn); +	P2PVR::Events rtn; +	SqlContainerCreator<P2PVR::Events, P2PVR::Event> cc(rtn);  	cc.populate(Select(SI_eventsInSchedules).second);  	return rtn;  } -DVBSI::Events +P2PVR::Events  SI::EventsInSchedule(int scheduleId, const Ice::Current &)  { -	DVBSI::Events rtn; -	SqlContainerCreator<DVBSI::Events, DVBSI::Event> cc(rtn); +	P2PVR::Events rtn; +	SqlContainerCreator<P2PVR::Events, P2PVR::Event> cc(rtn);  	cc.populate(Select(SI_eventsInSchedule, scheduleId).second);  	return rtn;  } diff --git a/p2pvr/daemon/si.h b/p2pvr/daemon/si.h index dd48d77..21b78e1 100644 --- a/p2pvr/daemon/si.h +++ b/p2pvr/daemon/si.h @@ -14,12 +14,13 @@ class SI : public P2PVR::SI, public DatabaseClient {  		DVBSI::ServiceList GetServices(const Ice::Current &);  		DVBSI::ServicePtr GetService(int id, const Ice::Current &); -		DVBSI::EventPtr GetEvent(int serviceId, int eventId, const Ice::Current &); -		DVBSI::Events EventsOnNow(const Ice::Current &); -		DVBSI::Events EventsInSchedules(const Ice::Current &); -		DVBSI::Events EventsInSchedule(int scheduleId, const Ice::Current &); -		DVBSI::Events EventsInRange(const Common::DateTime &, const Common::DateTime &, const Ice::Current &); -    DVBSI::Events EventSearch(const IceUtil::Optional<std::string> & keywords, const IceUtil::Optional<Ice::Int> & serviceId, const IceUtil::Optional<Common::DateTime> & from, const IceUtil::Optional<Common::DateTime> & to, const Ice::Current &); +		P2PVR::Events GetEvents(const P2PVR::IntSequence & eventUids, const Ice::Current &); +		P2PVR::EventPtr GetEvent(int serviceId, int eventId, const Ice::Current &); +		P2PVR::Events EventsOnNow(const Ice::Current &); +		P2PVR::Events EventsInSchedules(const Ice::Current &); +		P2PVR::Events EventsInSchedule(int scheduleId, const Ice::Current &); +		P2PVR::Events EventsInRange(const Common::DateTime &, const Common::DateTime &, const Ice::Current &); +		P2PVR::Events EventSearch(const IceUtil::Optional<std::string> & keywords, const IceUtil::Optional<Ice::Int> & serviceId, const IceUtil::Optional<Common::DateTime> & from, const IceUtil::Optional<Common::DateTime> & to, const Ice::Current &);  };  #endif diff --git a/p2pvr/daemon/sql/Maint_pruneEvents.sql b/p2pvr/daemon/sql/Maint_pruneEvents.sql new file mode 100644 index 0000000..b6f1d1b --- /dev/null +++ b/p2pvr/daemon/sql/Maint_pruneEvents.sql @@ -0,0 +1,4 @@ +DELETE FROM events e +WHERE e.eventuid NOT IN (SELECT eventuid FROM recorded) +AND e.eventuid NOT IN (SELECT eventuid FROM recordings) +AND NOT current diff --git a/p2pvr/daemon/sql/Recordings_getAll.sql b/p2pvr/daemon/sql/Recordings_getAll.sql index c0a096c..3c3ff51 100644 --- a/p2pvr/daemon/sql/Recordings_getAll.sql +++ b/p2pvr/daemon/sql/Recordings_getAll.sql @@ -1,3 +1,3 @@ -SELECT recordingId, storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration +SELECT recordingId, storageAddress, guid, scheduleId, eventUid  FROM recordings r -ORDER BY startTime, title, subtitle +ORDER BY recordingId diff --git a/p2pvr/daemon/sql/Recordings_insert.sql b/p2pvr/daemon/sql/Recordings_insert.sql index dfe2ccc..ba0b9e2 100644 --- a/p2pvr/daemon/sql/Recordings_insert.sql +++ b/p2pvr/daemon/sql/Recordings_insert.sql @@ -1,2 +1,2 @@ -INSERT INTO recordings(storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration) -VALUES(?, ?, ?, ?, ?, ?, ?, ?) +INSERT INTO recordings(storageAddress, guid, scheduleId, eventUid) +VALUES(?, ?, ?, ?) diff --git a/p2pvr/daemon/sql/SI_eventById.sql b/p2pvr/daemon/sql/SI_eventById.sql index f0e028d..b751ad6 100644 --- a/p2pvr/daemon/sql/SI_eventById.sql +++ b/p2pvr/daemon/sql/SI_eventById.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select +	e.serviceid,  	e.eventid,  	e.title,  	e.titlelang, @@ -21,8 +22,11 @@ select e.serviceid,  	e.episodes,  	e.year,  	e.flags, -	e.season +	e.season, +	e.eventuid, +	e.current  from events e -where serviceid  = ? +where serviceid = ?  and eventid = ? +and current diff --git a/p2pvr/daemon/sql/SI_eventByUid.sql b/p2pvr/daemon/sql/SI_eventByUid.sql new file mode 100644 index 0000000..1d559ec --- /dev/null +++ b/p2pvr/daemon/sql/SI_eventByUid.sql @@ -0,0 +1,30 @@ +select +	e.serviceid, +	e.eventid, +	e.title, +	e.titlelang, +	e.subtitle, +	e.description, +	e.descriptionlang, +	e.videoaspect, +	e.videoframerate, +	e.videohd, +	e.audiochannels, +	e.audiolanguage, +	e.subtitlelanguage, +	e.category, +	e.subcategory, +	e.usercategory, +	e.dvbrating, +	e.starttime, +	e.stoptime, +	e.episode, +	e.episodes, +	e.year, +	e.flags, +	e.season, +	e.eventuid, +	e.current +from events e +where eventuid = ? + diff --git a/p2pvr/daemon/sql/SI_eventSearch.sql b/p2pvr/daemon/sql/SI_eventSearch.sql index 7ff0cf7..ffbe93f 100644 --- a/p2pvr/daemon/sql/SI_eventSearch.sql +++ b/p2pvr/daemon/sql/SI_eventSearch.sql @@ -22,11 +22,14 @@ select  	e.episodes,  	e.year,  	e.flags, -	e.season +	e.season, +	e.eventuid, +	e.current  from events e  where tsrange(?, ?, '[)') && tsrange(e.starttime, e.stoptime)  and (e.serviceId = ? or ?::int is null)  and (event_tsvector(e) @@ plainto_tsquery(?) or ?::text is null) +and current  order by  	max(ts_rank(event_tsvector(e), plainto_tsquery(?))) over(partition by title) desc,  	max(ts_rank(event_tsvector(e), plainto_tsquery(?))) over(partition by title, subtitle, description) desc, diff --git a/p2pvr/daemon/sql/SI_eventsInRange.sql b/p2pvr/daemon/sql/SI_eventsInRange.sql index 0a2d6de..1d0eb17 100644 --- a/p2pvr/daemon/sql/SI_eventsInRange.sql +++ b/p2pvr/daemon/sql/SI_eventsInRange.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select +	e.serviceid,  	e.eventid,  	e.title,  	e.titlelang, @@ -21,8 +22,11 @@ select e.serviceid,  	e.episodes,  	e.year,  	e.flags, -	e.season +	e.season, +	e.eventuid, +	e.current  from events e  where tsrange(?, ?, '[)') && tsrange(e.starttime, e.stoptime) +and current  order by e.serviceid, e.starttime diff --git a/p2pvr/daemon/sql/SI_eventsInSchedule.sql b/p2pvr/daemon/sql/SI_eventsInSchedule.sql index 3f919a5..72ae26e 100644 --- a/p2pvr/daemon/sql/SI_eventsInSchedule.sql +++ b/p2pvr/daemon/sql/SI_eventsInSchedule.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select +	e.serviceid,  	e.eventid,  	e.title,  	e.titlelang, @@ -21,10 +22,12 @@ select e.serviceid,  	e.episodes,  	e.year,  	e.flags, -	e.season +	e.season, +	e.eventuid, +	e.current  from events e, record r -where e.serviceid = r.serviceid -and e.eventid = r.eventid +where e.eventuid = r.eventuid  and r.scheduleid = ? +and e.current  order by e.serviceid, e.starttime diff --git a/p2pvr/daemon/sql/SI_eventsInSchedules.sql b/p2pvr/daemon/sql/SI_eventsInSchedules.sql index bd4637a..880b28a 100644 --- a/p2pvr/daemon/sql/SI_eventsInSchedules.sql +++ b/p2pvr/daemon/sql/SI_eventsInSchedules.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select +	e.serviceid,  	e.eventid,  	e.title,  	e.titlelang, @@ -21,9 +22,11 @@ select e.serviceid,  	e.episodes,  	e.year,  	e.flags, -	e.season +	e.season, +	e.eventuid, +	e.current  from events e, record r -where e.serviceid = r.serviceid -and e.eventid = r.eventid +where e.eventuid = r.eventuid +and current  order by e.serviceid, e.starttime diff --git a/p2pvr/daemon/sql/SI_eventsOnNow.sql b/p2pvr/daemon/sql/SI_eventsOnNow.sql index 36760b4..391e8de 100644 --- a/p2pvr/daemon/sql/SI_eventsOnNow.sql +++ b/p2pvr/daemon/sql/SI_eventsOnNow.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select +	e.serviceid,  	e.eventid,  	e.title,  	e.titlelang, @@ -21,7 +22,10 @@ select e.serviceid,  	e.episodes,  	e.year,  	e.flags, -	e.season +	e.season, +	e.eventuid, +	e.current  from events e  where now()::timestamp without time zone <@ tsrange(e.starttime, e.stoptime) +and current  order by e.serviceid diff --git a/p2pvr/daemon/sql/SI_serviceNextUsed.sql b/p2pvr/daemon/sql/SI_serviceNextUsed.sql index 8e906ad..1bf2053 100644 --- a/p2pvr/daemon/sql/SI_serviceNextUsed.sql +++ b/p2pvr/daemon/sql/SI_serviceNextUsed.sql @@ -1,12 +1,11 @@  SELECT dd.*  FROM delivery_dvbt dd, services s -	LEFT OUTER JOIN record r -		ON r.serviceid = s.serviceid -		AND r.recordstatus = 0  	LEFT OUTER JOIN events e -		ON r.eventid = e.eventid -		AND r.serviceid = e.serviceid +		ON s.serviceid = e.serviceid  		AND e.starttime > NOW() +	LEFT OUTER JOIN record r +		ON r.eventuid = e.eventuid +		AND r.recordstatus = 0  WHERE dd.transportstreamid = s.transportstreamid  ORDER BY e.starttime, s.serviceid  LIMIT 1 diff --git a/p2pvr/daemon/sql/Schedules_GetCandidates.sql b/p2pvr/daemon/sql/Schedules_GetCandidates.sql index 8e8b15e..0bb7bd8 100644 --- a/p2pvr/daemon/sql/Schedules_GetCandidates.sql +++ b/p2pvr/daemon/sql/Schedules_GetCandidates.sql @@ -1,25 +1,26 @@ -select what, serviceid, eventid, transportstreamid, +select what, eventuid, transportstreamid,  	starttime - early starttime, stoptime + late stoptime,  	priority, scheduleid  from ( -	select (e.title, e.subtitle, e.description)::text what, e.serviceid, e.eventid, sv.transportstreamid, +	select (e.title, e.subtitle, e.description)::text what, e.eventuid, sv.transportstreamid,  		e.starttime, e.stoptime - interval '1 second' stoptime,  		s.early, s.late, s.scheduleid, s.priority, -		rank() over(partition by e.serviceid, e.eventid, sv.serviceid order by s.priority desc, s.scheduleid) schedulerank +		rank() over(partition by e.eventuid, sv.serviceid order by s.priority desc, s.scheduleid) schedulerank  	from services sv, events e, schedules s  	where (s.serviceid is null or s.serviceid = e.serviceid)  	and (s.title is null or lower(s.title) = lower(e.title)) -	and (s.eventid is null or s.eventid = e.eventid) +	and (s.eventuid is null or s.eventuid = e.eventuid)  	and (s.search is null or event_tsvector(e) @@ plainto_tsquery(s.search))  	and sv.serviceid = e.serviceid  	and e.stoptime > now()  	and not exists (  		select 1 -		from recorded r -		where lower(e.title) = lower(r.title) -		and coalesce(lower(e.subtitle), '') = coalesce(lower(r.subtitle), '') -		and ts_rank(to_tsvector(e.description), plainto_tsquery(r.description)) + -			ts_rank(to_tsvector(r.description), plainto_tsquery(e.description)) > 1)) e +		from recorded r, events re +		where r.eventuid = re.eventuid +		and lower(e.title) = lower(re.title) +		and coalesce(lower(e.subtitle), '') = coalesce(lower(re.subtitle), '') +		and ts_rank(to_tsvector(e.description), plainto_tsquery(re.description)) + +			ts_rank(to_tsvector(re.description), plainto_tsquery(e.description)) > 1)) e  where e.schedulerank = 1  order by e.priority desc, e.what, e.transportstreamid, e.starttime diff --git a/p2pvr/daemon/sql/Schedules_insert.sql b/p2pvr/daemon/sql/Schedules_insert.sql index 100e78b..70c95bd 100644 --- a/p2pvr/daemon/sql/Schedules_insert.sql +++ b/p2pvr/daemon/sql/Schedules_insert.sql @@ -1,2 +1,2 @@ -INSERT INTO schedules(serviceId, eventId, title, search, priority, early, late, repeats) +INSERT INTO schedules(serviceId, eventUid, title, search, priority, early, late, repeats)  VALUES(?, ?, ?, ?, ?, ?, ?, ?) diff --git a/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql b/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql index 3874c37..09e9b4c 100644 --- a/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql +++ b/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql @@ -1,8 +1,7 @@ -SELECT r.serviceid, r.eventid, r.scheduleid +SELECT e.serviceid, e.eventid, r.scheduleid  FROM record r, events e, schedules s  WHERE recordstatus = 0 -AND r.serviceid = e.serviceid -AND r.eventid = e.eventid +AND r.eventuid = e.eventuid  AND r.scheduleid = s.scheduleid  AND e.stoptime + s.late > NOW()  ORDER BY e.starttime, e.serviceid diff --git a/p2pvr/daemon/sql/Schedules_selectAll.sql b/p2pvr/daemon/sql/Schedules_selectAll.sql index e9e500e..56778a9 100644 --- a/p2pvr/daemon/sql/Schedules_selectAll.sql +++ b/p2pvr/daemon/sql/Schedules_selectAll.sql @@ -1,3 +1,3 @@ -SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats +SELECT scheduleid, serviceid, eventuid, title, search, priority, early, late, repeats  FROM schedules  ORDER BY scheduleId diff --git a/p2pvr/daemon/sql/Schedules_selectById.sql b/p2pvr/daemon/sql/Schedules_selectById.sql index 4990418..291398c 100644 --- a/p2pvr/daemon/sql/Schedules_selectById.sql +++ b/p2pvr/daemon/sql/Schedules_selectById.sql @@ -1,5 +1,4 @@ -SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats +SELECT scheduleid, serviceid, eventuid, title, search, priority, early, late, repeats  FROM schedules  WHERE scheduleid = ? -ORDER BY scheduleId diff --git a/p2pvr/daemon/sql/Schedules_update.sql b/p2pvr/daemon/sql/Schedules_update.sql index 56c9531..cf3ce49 100644 --- a/p2pvr/daemon/sql/Schedules_update.sql +++ b/p2pvr/daemon/sql/Schedules_update.sql @@ -1,6 +1,6 @@  UPDATE schedules SET  	serviceId = ?, -	eventId = ?, +	eventUid = ?,  	title = ?,  	search = ?,  	priority = ?, diff --git a/p2pvr/daemon/unittests/Jamfile.jam b/p2pvr/daemon/unittests/Jamfile.jam index d0d704d..e41b164 100644 --- a/p2pvr/daemon/unittests/Jamfile.jam +++ b/p2pvr/daemon/unittests/Jamfile.jam @@ -16,6 +16,7 @@ unit-test testp2ice :  	<library>../..//p2ice  	<library>../..//p2ut  	<dependency>../../ice//p2pvrice +	<dependency>../../lib//p2pvrlib  	<dependency>../../p2comp//p2pvrp2comp  	<library>boost_system  	<library>boost_filesystem @@ -24,7 +25,7 @@ unit-test testp2ice :  	;  unit-test testMaint : -	testMaint.cpp +	testMaint.cpp mockDevices.cpp mockScheduler.cpp  	:  	<define>BOOST_TEST_DYN_LINK  	<library>../..//p2common @@ -43,4 +44,61 @@ unit-test testMaint :  	<define>ROOT=\"$(me)\"  	; +unit-test testRecordings : +	testRecordings.cpp +	: +	<define>BOOST_TEST_DYN_LINK +	<library>../..//p2common +	<library>../..//p2basics +	<library>../..//p2lib +	<library>../..//p2ice +	<library>../..//p2xml +	<library>../..//p2ut +	<library>..//p2pvrdaemon +	<library>IceUtil +	<library>Ice +	<library>boost_system +	<library>boost_filesystem +	<library>../..//boost_utf +	<define>ROOT=\"$(me)\" +	; + +unit-test testSi : +	testSi.cpp +	: +	<define>BOOST_TEST_DYN_LINK +	<library>../..//p2common +	<library>../..//p2basics +	<library>../..//p2lib +	<library>../..//p2ice +	<library>../..//p2xml +	<library>../..//p2ut +	<library>..//p2pvrdaemon +	<library>IceUtil +	<library>Ice +	<library>boost_system +	<library>boost_filesystem +	<library>../..//boost_utf +	<define>ROOT=\"$(me)\" +	; + +unit-test testSched : +	testSched.cpp mockDevices.cpp mockRecorder.cpp +	: +	<define>BOOST_TEST_DYN_LINK +	<library>../..//p2common +	<library>../..//p2basics +	<library>../..//p2lib +	<library>../..//p2ice +	<library>../..//p2xml +	<library>../..//p2ut +	<library>..//p2pvrdaemon +	<library>IceUtil +	<library>Ice +	<library>boost_system +	<library>boost_filesystem +	<library>../../devices//p2pvrMockTuner +	<library>../..//boost_utf +	<define>ROOT=\"$(me)\" +	; diff --git a/p2pvr/daemon/unittests/mockDevices.cpp b/p2pvr/daemon/unittests/mockDevices.cpp new file mode 100644 index 0000000..7c3dc2c --- /dev/null +++ b/p2pvr/daemon/unittests/mockDevices.cpp @@ -0,0 +1,29 @@ +#include "mockDevices.h" +#include <mockTuner.h> +#include <Ice/ObjectAdapter.h> + +P2PVR::TunerPrx MockDevices::GetTunerSpecific(const DVBSI::DeliveryPtr&, const Ice::Current & ice) +{ +	return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); +} + +P2PVR::TunerPrx MockDevices::GetTunerAny(Ice::Short, const DVBSI::DeliveryPtr&, const Ice::Current & ice) +{ +	return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); +} + +P2PVR::PrivateTunerPrx MockDevices::GetPrivateTuner(Ice::Short, const Ice::Current & ice) +{ +	return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); +} + +void MockDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) +{ +	ice.adapter->remove(tuner->ice_getIdentity()); +} + +Ice::Int MockDevices::TunerCount(const Ice::Current&) +{ +	return 1; +} + diff --git a/p2pvr/daemon/unittests/mockDevices.h b/p2pvr/daemon/unittests/mockDevices.h new file mode 100644 index 0000000..59d1b50 --- /dev/null +++ b/p2pvr/daemon/unittests/mockDevices.h @@ -0,0 +1,16 @@ +#ifndef P2PVR_MOCKS_DEVICES_H +#define P2PVR_MOCKS_DEVICES_H + +#include <dvb.h> + +class MockDevices : public P2PVR::Devices { +	public: +		P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr&, const Ice::Current & ice) override; +		P2PVR::TunerPrx GetTunerAny(Ice::Short, const DVBSI::DeliveryPtr&, const Ice::Current & ice) override; +		P2PVR::PrivateTunerPrx GetPrivateTuner(Ice::Short, const Ice::Current & ice) override; +		void ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) override; +		Ice::Int TunerCount(const Ice::Current&) override; +}; + +#endif + diff --git a/p2pvr/daemon/unittests/mockRecorder.cpp b/p2pvr/daemon/unittests/mockRecorder.cpp new file mode 100644 index 0000000..0796aba --- /dev/null +++ b/p2pvr/daemon/unittests/mockRecorder.cpp @@ -0,0 +1,8 @@ +#include "mockRecorder.h" + +void +MockRecorder::RefreshSchedules(const Ice::Current &) +{ + +} + diff --git a/p2pvr/daemon/unittests/mockRecorder.h b/p2pvr/daemon/unittests/mockRecorder.h new file mode 100644 index 0000000..85f747b --- /dev/null +++ b/p2pvr/daemon/unittests/mockRecorder.h @@ -0,0 +1,12 @@ +#ifndef P2PVR_MOCKS_RECORDER_H +#define P2PVR_MOCKS_RECORDER_H + +#include <p2pvr.h> + +class MockRecorder : public P2PVR::Recorder { +	public: +		void RefreshSchedules(const Ice::Current &) override; +}; + +#endif + diff --git a/p2pvr/daemon/unittests/mockScheduler.cpp b/p2pvr/daemon/unittests/mockScheduler.cpp new file mode 100644 index 0000000..2677df7 --- /dev/null +++ b/p2pvr/daemon/unittests/mockScheduler.cpp @@ -0,0 +1,36 @@ +#include "mockScheduler.h" + +void +MockScheduler::DoReschedule(const::Ice::Current &) +{ +} + +void +MockScheduler::DeleteSchedule(Ice::Int, const Ice::Current &) +{ +} + +P2PVR::SchedulePtr +MockScheduler::GetSchedule(::Ice::Int, const::Ice::Current &) +{ +	return P2PVR::SchedulePtr(); +} + +P2PVR::ScheduleList +MockScheduler::GetSchedules(const::Ice::Current &) +{ +	return P2PVR::ScheduleList(); +} + +P2PVR::ScheduledToRecordList +MockScheduler::GetScheduledToRecord(const::Ice::Current &) +{ +	return P2PVR::ScheduledToRecordList(); +} + +Ice::Int +MockScheduler::UpdateSchedule(const::P2PVR::SchedulePtr &, const::Ice::Current &) +{ +	return 0; +} + diff --git a/p2pvr/daemon/unittests/mockScheduler.h b/p2pvr/daemon/unittests/mockScheduler.h new file mode 100644 index 0000000..9176bb6 --- /dev/null +++ b/p2pvr/daemon/unittests/mockScheduler.h @@ -0,0 +1,17 @@ +#ifndef P2PVR_MOCKS_SCHEDULER_H +#define P2PVR_MOCKS_SCHEDULER_H + +#include <p2pvr.h> + +class MockScheduler : public P2PVR::Schedules { +	public: +		void DoReschedule(const ::Ice::Current&) override; +		void DeleteSchedule(Ice::Int, const Ice::Current&) override; +		P2PVR::SchedulePtr GetSchedule(::Ice::Int, const ::Ice::Current&) override; +		P2PVR::ScheduleList GetSchedules(const ::Ice::Current&) override; +		P2PVR::ScheduledToRecordList GetScheduledToRecord(const ::Ice::Current&) override; +		Ice::Int UpdateSchedule(const ::P2PVR::SchedulePtr&, const ::Ice::Current&) override; +}; + +#endif + diff --git a/p2pvr/daemon/unittests/testMaint.cpp b/p2pvr/daemon/unittests/testMaint.cpp index 139284c..10f365e 100644 --- a/p2pvr/daemon/unittests/testMaint.cpp +++ b/p2pvr/daemon/unittests/testMaint.cpp @@ -7,100 +7,90 @@  #include <scopeObject.h>  #include <maintenance.h>  #include <mockTuner.h> +#include "mockDevices.h" +#include "mockScheduler.h"  #include <si.h> +#include <recordings.h>  #include <linux/dvb/frontend.h> +#include <definedDirs.h> -#define XSTR(s) STR(s) -#define STR(s) #s -const auto bindir = boost::filesystem::canonical("/proc/self/exe").parent_path(); -const auto componentdir = bindir.parent_path() / "component"; -const boost::filesystem::path root(XSTR(ROOT)); - -class MockDevices : public P2PVR::Devices { +class Core {  	public: -		P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr&, const Ice::Current & ice) override -		{ -			return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); -		} -		P2PVR::TunerPrx GetTunerAny(Ice::Short, const DVBSI::DeliveryPtr&, const Ice::Current & ice) override -		{ -			return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); -		} -		P2PVR::PrivateTunerPrx GetPrivateTuner(Ice::Short, const Ice::Current & ice) override -		{ -			return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); -		} -		void ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) override +		Core()  		{ -			ice.adapter->remove(tuner->ice_getIdentity()); +			int paramCount = 0; +			ic = Ice::initialize(paramCount, NULL); +			auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12000"); +			TestOptionsSource::LoadTestOptions({ +					{ "common.datasourceRoot", (RootDir / "datasources").string() }, +				}); +			adapter->add(new MockDevices(), ic->stringToIdentity("GlobalDevices")); +			adapter->add(new MockScheduler(), ic->stringToIdentity("Schedules")); +			adapter->add(new SI(), ic->stringToIdentity("SI")); +			adapter->add(new Recordings(), ic->stringToIdentity("Recordings")); +			adapter->add(new Maintenance(adapter, NULL), ic->stringToIdentity("Maintenance")); +			adapter->activate(); + +			r = P2PVR::RecordingsPrx::checkedCast(ic->stringToProxy("Recordings")); +			BOOST_REQUIRE(r); +			r->ice_ping(); + +			s = P2PVR::SIPrx::checkedCast(ic->stringToProxy("SI")); +			BOOST_REQUIRE(s); +			s->ice_ping(); +	 +			m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); +			BOOST_REQUIRE(m); +			m->ice_ping();  		} -		Ice::Int TunerCount(const Ice::Current&) override + +		~Core()  		{ -			return 1; +			ic->destroy();  		} -}; -class MockScheduler : public P2PVR::Schedules { -	public: -		void DoReschedule(const ::Ice::Current&) { } -		void DeleteSchedule(Ice::Int, const Ice::Current&) { } -		P2PVR::SchedulePtr GetSchedule(::Ice::Int, const ::Ice::Current&) { return P2PVR::SchedulePtr(); } -		P2PVR::ScheduleList GetSchedules(const ::Ice::Current&) { return P2PVR::ScheduleList(); } -		P2PVR::ScheduledToRecordList GetScheduledToRecord(const ::Ice::Current&) { return P2PVR::ScheduledToRecordList(); } -		Ice::Int UpdateSchedule(const ::P2PVR::SchedulePtr&, const ::Ice::Current&) { return 0; } +		P2PVR::MaintenancePrx m; +		P2PVR::RecordingsPrx r; +		P2PVR::SIPrx s; + +	private: +		Ice::CommunicatorPtr ic;  }; -static -Ice::CommunicatorPtr -standardConfig() -{ -	int paramCount = 0; -	Ice::CommunicatorPtr ic = Ice::initialize(paramCount, NULL); -	auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12000"); -	TestOptionsSource::LoadTestOptions({ -			{ "common.datasourceRoot", (root / "datasources").string() }, -		}); -	adapter->add(new MockDevices(), ic->stringToIdentity("GlobalDevices")); -	adapter->add(new MockScheduler(), ic->stringToIdentity("Schedules")); -	adapter->add(new SI(), ic->stringToIdentity("SI")); -	adapter->add(new Maintenance(adapter, NULL), ic->stringToIdentity("Maintenance")); -	adapter->activate(); -	return ic; -} +BOOST_FIXTURE_TEST_SUITE( MaintCore, Core )  BOOST_AUTO_TEST_CASE( update_network )  { -	auto ic = standardConfig(); -	ScopeObject _([&ic]{ ic->destroy(); }); - -	auto m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); -	BOOST_REQUIRE(m); -	m->ice_ping(); -	  	m->UpdateNetwork(FE_OFDM);  }  BOOST_AUTO_TEST_CASE( update_services )  { -	auto ic = standardConfig(); -	ScopeObject _([&ic]{ ic->destroy(); }); - -	auto m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); -	BOOST_REQUIRE(m); -	m->ice_ping(); -	  	m->UpdateServices(FE_OFDM);  }  BOOST_AUTO_TEST_CASE( update_events )  { -	auto ic = standardConfig(); -	ScopeObject _([&ic]{ ic->destroy(); }); +	BOOST_CHECKPOINT("Get existing recordings"); +	auto recs = r->GetRecordings(); -	auto m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); -	BOOST_REQUIRE(m); -	m->ice_ping(); -	 +	BOOST_CHECKPOINT("Delete existing recordings"); +	BOOST_FOREACH(const auto & rec, recs) { +		r->DeleteRecording(rec->RecordingId); +	} + +	BOOST_CHECKPOINT("Write first events"); +	MockTuner::SetEventsSet(0);  	m->UpdateEvents(FE_OFDM); +	BOOST_REQUIRE(s->GetEvent(14448, 27052)); +	BOOST_REQUIRE_THROW(s->GetEvent(15856, 3591), P2PVR::NotFound); + +	BOOST_CHECKPOINT("Write second events"); +	MockTuner::SetEventsSet(1); +	m->UpdateEvents(FE_OFDM); +	BOOST_REQUIRE_THROW(s->GetEvent(14448, 27052), P2PVR::NotFound); +	BOOST_REQUIRE(s->GetEvent(15856, 3591));  } +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testRecordings.cpp b/p2pvr/daemon/unittests/testRecordings.cpp new file mode 100644 index 0000000..adfc231 --- /dev/null +++ b/p2pvr/daemon/unittests/testRecordings.cpp @@ -0,0 +1,74 @@ +#define BOOST_TEST_MODULE Recordings +#include <boost/test/unit_test.hpp> +#include <boost/filesystem/operations.hpp> +#include <testOptionsSource.h> +#include <Ice/ObjectAdapter.h> +#include <Ice/Service.h> +#include <scopeObject.h> +#include <maintenance.h> +#include <mockTuner.h> +#include <si.h> +#include <recordings.h> +#include <linux/dvb/frontend.h> +#include <definedDirs.h> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/uuid/uuid_io.hpp> +#include <boost/lexical_cast.hpp> + +class Core { +	public: +		Core() +		{ +			int paramCount = 0; +			ic = Ice::initialize(paramCount, NULL); +			auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12001"); +			TestOptionsSource::LoadTestOptions({ +					{ "common.datasourceRoot", (RootDir / "datasources").string() }, +				}); +			adapter->add(new Recordings(), ic->stringToIdentity("Recordings")); +			adapter->add(new SI(), ic->stringToIdentity("SI")); +			adapter->activate(); + +			r = P2PVR::RecordingsPrx::checkedCast(ic->stringToProxy("Recordings")); +			BOOST_REQUIRE(r); +			r->ice_ping(); +	 +			si = P2PVR::SIPrx::checkedCast(ic->stringToProxy("SI")); +			BOOST_REQUIRE(si); +			si->ice_ping(); +		} + +		~Core() +		{ +			ic->destroy(); +		} + +		P2PVR::SIPrx si; +		P2PVR::RecordingsPrx r; + +	private: +		Ice::CommunicatorPtr ic; +}; + +BOOST_FIXTURE_TEST_SUITE( RecCore, Core ) + +BOOST_AUTO_TEST_CASE( recordings_get ) +{ +	r->GetRecordings(); +} + +BOOST_AUTO_TEST_CASE( recordings_addAndDelete ) +{ +	auto event = si->GetEvent(5696, 40124); +	BOOST_REQUIRE(event); +	BOOST_MESSAGE(event->Title); + +	auto guid = boost::lexical_cast<std::string>(boost::uuids::random_generator()()); +	auto rec = P2PVR::RecordingPtr(new P2PVR::Recording(0, "", guid, 0, event->EventUid)); +	auto id = r->NewRecording(rec); +	r->GetRecordings(); +	r->DeleteRecording(id); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testSched.cpp b/p2pvr/daemon/unittests/testSched.cpp new file mode 100644 index 0000000..9a6134b --- /dev/null +++ b/p2pvr/daemon/unittests/testSched.cpp @@ -0,0 +1,102 @@ +#define BOOST_TEST_MODULE Scheduler +#include <boost/test/unit_test.hpp> +#include <boost/filesystem/operations.hpp> +#include <testOptionsSource.h> +#include <Ice/ObjectAdapter.h> +#include <Ice/Service.h> +#include <maintenance.h> +#include <mockTuner.h> +#include <si.h> +#include <schedules.h> +#include "mockDevices.h" +#include "mockRecorder.h" +#include <definedDirs.h> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/uuid/uuid_io.hpp> +#include <boost/lexical_cast.hpp> +#include <commonHelpers.h> + +class Core { +	public: +		Core() +		{ +			int paramCount = 0; +			ic = Ice::initialize(paramCount, NULL); +			auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12003"); +			TestOptionsSource::LoadTestOptions({ +					{ "common.datasourceRoot", (RootDir / "datasources").string() }, +				}); +			adapter->add(new Schedules(), ic->stringToIdentity("Schedules")); +			adapter->add(new MockDevices(), ic->stringToIdentity("GlobalDevices")); +			adapter->add(new MockRecorder(), ic->stringToIdentity("Recorder")); +			adapter->activate(); + +			sc = P2PVR::SchedulesPrx::checkedCast(ic->stringToProxy("Schedules")); +			BOOST_REQUIRE(sc); +			sc->ice_ping(); +		} + +		~Core() +		{ +			ic->destroy(); +		} + +		P2PVR::SchedulesPrx sc; + +	private: +		Ice::CommunicatorPtr ic; +}; + +BOOST_FIXTURE_TEST_SUITE( ScCore, Core ) + +BOOST_AUTO_TEST_CASE( sc_getSchedules ) +{ +	sc->GetSchedules(); +} + +BOOST_AUTO_TEST_CASE( sc_doReschedule ) +{ +	sc->DoReschedule(); +} + +BOOST_AUTO_TEST_CASE( sc_getScheduled ) +{ +	sc->GetScheduledToRecord(); +} + +BOOST_AUTO_TEST_CASE( sc_crud ) +{ +	P2PVR::SchedulePtr schedule = new P2PVR::Schedule(); +	schedule->Search = "Top Gear"; + +	auto id = sc->UpdateSchedule(schedule); +	BOOST_REQUIRE(id > 0); +	schedule->ScheduleId = id; + +	auto fetched = sc->GetSchedule(id); +	BOOST_REQUIRE_EQUAL(schedule->ScheduleId, fetched->ScheduleId); +	BOOST_REQUIRE_EQUAL(*schedule->Search, *fetched->Search); +	BOOST_REQUIRE_EQUAL(schedule->Priority, fetched->Priority); +	BOOST_REQUIRE_EQUAL(schedule->Repeats, fetched->Repeats); +	BOOST_REQUIRE_EQUAL(schedule->Early, fetched->Early); +	BOOST_REQUIRE_EQUAL(schedule->Late, fetched->Late); + +	schedule->Search = "Top Gear Special"; +	schedule->Early.Minutes = 5; +	schedule->Late.Minutes = 15; +	auto updatedId = sc->UpdateSchedule(schedule); + +	fetched = sc->GetSchedule(id); +	BOOST_REQUIRE_EQUAL(updatedId, id); +	BOOST_REQUIRE_EQUAL(schedule->ScheduleId, fetched->ScheduleId); +	BOOST_REQUIRE_EQUAL(*schedule->Search, *fetched->Search); +	BOOST_REQUIRE_EQUAL(schedule->Priority, fetched->Priority); +	BOOST_REQUIRE_EQUAL(schedule->Repeats, fetched->Repeats); +	BOOST_REQUIRE_EQUAL(schedule->Early, fetched->Early); +	BOOST_REQUIRE_EQUAL(schedule->Late, fetched->Late); + +	sc->DeleteSchedule(fetched->ScheduleId); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testSi.cpp b/p2pvr/daemon/unittests/testSi.cpp new file mode 100644 index 0000000..d191b38 --- /dev/null +++ b/p2pvr/daemon/unittests/testSi.cpp @@ -0,0 +1,105 @@ +#define BOOST_TEST_MODULE SI +#include <boost/test/unit_test.hpp> +#include <boost/filesystem/operations.hpp> +#include <testOptionsSource.h> +#include <Ice/ObjectAdapter.h> +#include <Ice/Service.h> +#include <maintenance.h> +#include <mockTuner.h> +#include <si.h> +#include <linux/dvb/frontend.h> +#include <definedDirs.h> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/uuid/uuid_io.hpp> +#include <boost/lexical_cast.hpp> + +class Core { +	public: +		Core() +		{ +			int paramCount = 0; +			ic = Ice::initialize(paramCount, NULL); +			auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12002"); +			TestOptionsSource::LoadTestOptions({ +					{ "common.datasourceRoot", (RootDir / "datasources").string() }, +				}); +			adapter->add(new SI(), ic->stringToIdentity("SI")); +			adapter->activate(); + +			si = P2PVR::SIPrx::checkedCast(ic->stringToProxy("SI")); +			BOOST_REQUIRE(si); +			si->ice_ping(); +		} + +		~Core() +		{ +			ic->destroy(); +		} + +		P2PVR::SIPrx si; + +	private: +		Ice::CommunicatorPtr ic; +}; + +BOOST_FIXTURE_TEST_SUITE( SiCore, Core ) + +BOOST_AUTO_TEST_CASE ( si_getEvents ) +{ +	// Get an event known to exist so we can use its uid +	auto event = si->GetEvent(23968, 4378); +	BOOST_REQUIRE(event); + +	auto events = si->GetEvents({ event->EventUid }); +	BOOST_REQUIRE_EQUAL(events.size(), 1); +	BOOST_REQUIRE_EQUAL(events.front()->ServiceId, 23968); +	BOOST_REQUIRE_EQUAL(events.front()->EventId, 4378); +} + +BOOST_AUTO_TEST_CASE ( si_getEvents_missing ) +{ +	BOOST_REQUIRE_THROW(si->GetEvents({ 0 }), P2PVR::NotFound); +} + +BOOST_AUTO_TEST_CASE( si_getEvent ) +{ +	auto event = si->GetEvent(23968, 4378); +	BOOST_REQUIRE(event); +	BOOST_REQUIRE_EQUAL(event->Title, "Timothy Goes to School"); +	BOOST_REQUIRE_EQUAL(event->Current, true); +} + +BOOST_AUTO_TEST_CASE( si_getEventsOnNow ) +{ +	si->EventsOnNow(); +} + +BOOST_AUTO_TEST_CASE( si_getEventsInSched ) +{ +	si->EventsInSchedule(0); +} + +BOOST_AUTO_TEST_CASE( si_getEventsInScheds ) +{ +	si->EventsInSchedules(); +} + +BOOST_AUTO_TEST_CASE( si_getEventsInRange ) +{ +	si->EventsInRange(Common::DateTime {2014, 12, 19, 3, 0}, Common::DateTime {2014, 12, 20, 3, 0}); +} + +BOOST_AUTO_TEST_CASE( si_getEventSearch ) +{ +	si->EventSearch("Top Gear", IceUtil::Optional< ::Ice::Int >(), +			IceUtil::Optional<Common::DateTime>(), IceUtil::Optional<Common::DateTime>()); +	si->EventSearch("Top Gear", 22272, +			IceUtil::Optional<Common::DateTime>(), IceUtil::Optional<Common::DateTime>()); +	si->EventSearch("Top Gear", 22272, +			Common::DateTime {2014, 12, 19, 3, 0}, IceUtil::Optional<Common::DateTime>()); +	si->EventSearch("Top Gear", 22272, +			Common::DateTime {2014, 12, 19, 3, 0}, Common::DateTime {2014, 12, 20, 3, 0}); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testp2ice.cpp b/p2pvr/daemon/unittests/testp2ice.cpp index 9f9e9a8..23fcbdc 100644 --- a/p2pvr/daemon/unittests/testp2ice.cpp +++ b/p2pvr/daemon/unittests/testp2ice.cpp @@ -2,18 +2,37 @@  #include <boost/test/unit_test.hpp>  #include <boost/filesystem/operations.hpp>  #include <testOptionsSource.h> +#include <definedDirs.h> +#include <sourceObject.h> -#define XSTR(s) STR(s) -#define STR(s) #s -const auto bindir = boost::filesystem::canonical("/proc/self/exe").parent_path(); -const boost::filesystem::path variant = bindir.leaf(); -const boost::filesystem::path compiler = bindir.parent_path().leaf(); -const boost::filesystem::path root = boost::filesystem::path(XSTR(ROOT)).parent_path().parent_path(); +const boost::filesystem::path variant = BinDir.leaf(); +const boost::filesystem::path compiler = BinDir.parent_path().leaf(); +const boost::filesystem::path root = RootDir.parent_path().parent_path();  const boost::filesystem::path iceroot = root / "ice"; +static +void +commonTests() +{ +	BOOST_REQUIRE(ElementLoader::getFor("p2pvrrecordingstream")); +	BOOST_REQUIRE(ElementLoader::getFor("p2pvrservicestream")); +	BOOST_REQUIRE(ElementLoader::getFor("P2PVR-SI-GetEvent")); +} + +static +void +unloadTests() +{ +	BOOST_REQUIRE_THROW(ElementLoader::getFor("P2PVR-SI-GetEvent"), NotSupported); +	// Known issue, these *should* unload, but for some reason, don't. +	BOOST_WARN_THROW(ElementLoader::getFor("p2pvrrecordingstream"), NotSupported); +	BOOST_WARN_THROW(ElementLoader::getFor("p2pvrservicestream"), NotSupported); +}  BOOST_AUTO_TEST_CASE( compile_client_clientOnly )  { +	TestOptionsSource::LoadTestOptions({ }); +  	const std::string tmpdir = "/tmp/ut/p2pvr.slice";  	BOOST_TEST_CHECKPOINT("Clean up");  	boost::filesystem::remove_all(tmpdir); @@ -23,13 +42,15 @@ BOOST_AUTO_TEST_CASE( compile_client_clientOnly )  			{ "ice.compile.tmpdir", tmpdir },  			{ "ice.client.slicerclient", (iceroot / "common.ice").string() },  			{ "library", (root / "ice" / "bin" / compiler / variant / "slicer-yes" / "libp2pvrice.so").string() }, +			{ "library", (root / "dvb" / "bin" / compiler / variant / "libp2pvrdvb.so").string() }, +			{ "library", (root / "lib" / "bin" / compiler / variant / "libp2pvrlib.so").string() },  			{ "library", (root / "p2comp" / "bin" / compiler / variant / "libp2pvrp2comp.so").string() },  			{ "ice.client.slicerclient", (iceroot / "dvbsi.ice").string() },  			{ "ice.client.slicerclient", (iceroot / "dvb.ice").string() },  			{ "ice.client.slicerclient", (iceroot / "p2pvr.ice").string() },  		}); -	//commonTests(); +	commonTests();  	TestOptionsSource::LoadTestOptions({ }); -	//unloadTests(); +	unloadTests();  } diff --git a/p2pvr/datasources/schema.sql b/p2pvr/datasources/schema.sql index 393325d..5e0612f 100644 --- a/p2pvr/datasources/schema.sql +++ b/p2pvr/datasources/schema.sql @@ -57,7 +57,9 @@ CREATE TABLE events (      episodes smallint,      year smallint,      flags text, -    season integer +    season integer, +    eventuid integer NOT NULL, +    current boolean DEFAULT true NOT NULL  ); @@ -128,6 +130,25 @@ CREATE TABLE delivery_dvbt (  -- +-- Name: events_eventuid_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE events_eventuid_seq +    START WITH 1 +    INCREMENT BY 1 +    NO MINVALUE +    NO MAXVALUE +    CACHE 1; + + +-- +-- Name: events_eventuid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE events_eventuid_seq OWNED BY events.eventuid; + + +--  -- Name: networks; Type: TABLE; Schema: public; Owner: -; Tablespace:   -- @@ -142,8 +163,7 @@ CREATE TABLE networks (  --  CREATE TABLE record ( -    serviceid integer NOT NULL, -    eventid integer NOT NULL, +    eventuid integer NOT NULL,      recordstatus integer NOT NULL,      recordingstatus integer DEFAULT 0 NOT NULL,      scheduleid integer NOT NULL @@ -157,11 +177,7 @@ CREATE TABLE record (  CREATE TABLE recorded (      recordedid integer NOT NULL,      scheduleid integer, -    title text, -    subtitle text, -    description text, -    starttime timestamp without time zone NOT NULL, -    duration interval NOT NULL +    eventuid integer NOT NULL  ); @@ -193,11 +209,7 @@ CREATE TABLE recordings (      storageaddress text NOT NULL,      guid text NOT NULL,      scheduleid integer NOT NULL, -    title text, -    subtitle text, -    description text, -    starttime timestamp without time zone NOT NULL, -    duration interval NOT NULL +    eventuid integer NOT NULL  ); @@ -227,7 +239,7 @@ ALTER SEQUENCE recordings_recordingid_seq OWNED BY recordings.recordingid;  CREATE TABLE schedules (      scheduleid integer NOT NULL,      serviceid integer, -    eventid integer, +    eventuid integer,      title text,      search text,      priority integer DEFAULT 0 NOT NULL, @@ -270,7 +282,7 @@ CREATE TABLE services (      eitschedule boolean,      eitpresentfollowing boolean,      freecamode boolean, -    transportstreamid integer NOT NULL +    transportstreamid integer  ); @@ -286,6 +298,13 @@ CREATE TABLE transportstreams (  -- +-- Name: eventuid; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY events ALTER COLUMN eventuid SET DEFAULT nextval('events_eventuid_seq'::regclass); + + +--  -- Name: recordedid; Type: DEFAULT; Schema: public; Owner: -  -- @@ -335,7 +354,7 @@ ALTER TABLE ONLY delivery_dvbt  --  ALTER TABLE ONLY events -    ADD CONSTRAINT pk_events PRIMARY KEY (serviceid, eventid); +    ADD CONSTRAINT pk_events PRIMARY KEY (eventuid);  -- @@ -367,7 +386,7 @@ ALTER TABLE ONLY recordings  --  ALTER TABLE ONLY record -    ADD CONSTRAINT pk_records PRIMARY KEY (serviceid, eventid); +    ADD CONSTRAINT pk_records PRIMARY KEY (eventuid);  -- @@ -423,20 +442,6 @@ CREATE INDEX idx_recorded_schedule ON recorded USING btree (scheduleid);  -- --- Name: idx_recorded_starttime; Type: INDEX; Schema: public; Owner: -; Tablespace:  --- - -CREATE INDEX idx_recorded_starttime ON recorded USING btree (starttime); - - --- --- Name: idx_recorded_title; Type: INDEX; Schema: public; Owner: -; Tablespace:  --- - -CREATE INDEX idx_recorded_title ON recorded USING btree (title); - - ---  -- Name: idx_recordings_schedule; Type: INDEX; Schema: public; Owner: -; Tablespace:   -- @@ -444,17 +449,10 @@ CREATE INDEX idx_recordings_schedule ON recordings USING btree (scheduleid);  -- --- Name: idx_recordings_starttime; Type: INDEX; Schema: public; Owner: -; Tablespace:  --- - -CREATE INDEX idx_recordings_starttime ON recordings USING btree (starttime); - - --- --- Name: idx_recordings_title; Type: INDEX; Schema: public; Owner: -; Tablespace:  +-- Name: uni_events_serviceevent; Type: INDEX; Schema: public; Owner: -; Tablespace:   -- -CREATE INDEX idx_recordings_title ON recordings USING btree (title); +CREATE UNIQUE INDEX uni_events_serviceevent ON events USING btree (serviceid, eventid) WHERE current;  -- @@ -489,6 +487,22 @@ ALTER TABLE ONLY delivery_dvbt  -- +-- Name: fk_record_eventuid; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY record +    ADD CONSTRAINT fk_record_eventuid FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- Name: fk_recorded_eventuid; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY recorded +    ADD CONSTRAINT fk_recorded_eventuid FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE; + + +--  -- Name: fk_recorded_schedule; Type: FK CONSTRAINT; Schema: public; Owner: -  -- @@ -497,11 +511,11 @@ ALTER TABLE ONLY recorded  -- --- Name: fk_records_event; Type: FK CONSTRAINT; Schema: public; Owner: - +-- Name: fk_recordings_eventuid; Type: FK CONSTRAINT; Schema: public; Owner: -  -- -ALTER TABLE ONLY record -    ADD CONSTRAINT fk_records_event FOREIGN KEY (serviceid, eventid) REFERENCES events(serviceid, eventid) ON UPDATE CASCADE ON DELETE CASCADE; +ALTER TABLE ONLY recordings +    ADD CONSTRAINT fk_recordings_eventuid FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE;  -- @@ -517,7 +531,7 @@ ALTER TABLE ONLY record  --  ALTER TABLE ONLY schedules -    ADD CONSTRAINT fk_schedule_event FOREIGN KEY (serviceid, eventid) REFERENCES events(serviceid, eventid) ON DELETE CASCADE; +    ADD CONSTRAINT fk_schedule_event FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE ON DELETE CASCADE;  -- @@ -533,7 +547,7 @@ ALTER TABLE ONLY schedules  --  ALTER TABLE ONLY services -    ADD CONSTRAINT fk_services_transportstreams FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE CASCADE; +    ADD CONSTRAINT fk_services_transportstreams FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE SET NULL;  -- diff --git a/p2pvr/devices/mockTuner.cpp b/p2pvr/devices/mockTuner.cpp index 335ddec..b89d533 100644 --- a/p2pvr/devices/mockTuner.cpp +++ b/p2pvr/devices/mockTuner.cpp @@ -23,6 +23,14 @@ ResourceFile(services);  ResourceFile(events1);  ResourceFile(events2); +int MockTuner::eventSet = 0; + +void +MockTuner::SetEventsSet(int n) +{ +	eventSet = n; +} +  void MockTuner::TuneTo(const DVBSI::DeliveryPtr &, const Ice::Current&)  {  } @@ -98,7 +106,7 @@ void MockTuner::SendProgramAssociationTable(const P2PVR::RawDataClientPrx &, con  void MockTuner::SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice)  { -	DecompressAndSendPackets(events1, client, ice); +	DecompressAndSendPackets(eventSet == 0 ? events1 : events2, client, ice);  }  int MockTuner::StartSendingTS(const P2PVR::PacketIds &, const P2PVR::RawDataClientPrx &, const Ice::Current &) diff --git a/p2pvr/devices/mockTuner.h b/p2pvr/devices/mockTuner.h index 220b535..31d12cb 100644 --- a/p2pvr/devices/mockTuner.h +++ b/p2pvr/devices/mockTuner.h @@ -6,7 +6,6 @@  class MockTuner : public P2PVR::PrivateTuner {  	public: -  		void TuneTo(const DVBSI::DeliveryPtr &, const Ice::Current&);  		int GetStatus(const Ice::Current&); @@ -24,8 +23,12 @@ class MockTuner : public P2PVR::PrivateTuner {  		Ice::Long GetLastUsedTime(const Ice::Current&); +		static void SetEventsSet(int n); +  	protected:  		void DecompressAndSendPackets(const Ice::ByteSeq &, const P2PVR::RawDataClientPrx &, const Ice::Current&) const; + +		static int eventSet;  };  #endif diff --git a/p2pvr/ice/common.ice b/p2pvr/ice/common.ice index 14ca155..c4be4ce 100644 --- a/p2pvr/ice/common.ice +++ b/p2pvr/ice/common.ice @@ -11,8 +11,8 @@ module Common {  	};  	struct Duration { -		short Hour; -		short Minute; +		short Hours = 0; +		short Minutes = 0;  	};  }; diff --git a/p2pvr/ice/commonHelpers.cpp b/p2pvr/ice/commonHelpers.cpp index 46c7fad..6ad120b 100644 --- a/p2pvr/ice/commonHelpers.cpp +++ b/p2pvr/ice/commonHelpers.cpp @@ -12,7 +12,7 @@ namespace Common {  	boost::posix_time::time_duration operator*(const Common::Duration & d)  	{ -		return boost::posix_time::time_duration(d.Hour, d.Minute, 0); +		return boost::posix_time::time_duration(d.Hours, d.Minutes, 0);  	}  } diff --git a/p2pvr/ice/commonHelpers.h b/p2pvr/ice/commonHelpers.h index cc3cac1..3f7e57d 100644 --- a/p2pvr/ice/commonHelpers.h +++ b/p2pvr/ice/commonHelpers.h @@ -18,6 +18,18 @@ namespace Common {  			<< ":" << std::setw(2) << std::setfill('0') << dt.Minute;  		return o;  	} + +	template<typename C, typename T> +	std::basic_ostream<C, T> & +	operator<<(std::basic_ostream<C, T> & o, const Common::Duration & d) +	{ +		if (d.Hours) { +			o << d.Hours << "hrs "; +		} +		o << d.Minutes << "min"; +		return o; +	} +  	boost::posix_time::ptime operator*(const Common::DateTime &);  	boost::posix_time::time_duration operator*(const Common::Duration &);  } diff --git a/p2pvr/ice/p2pvr.ice b/p2pvr/ice/p2pvr.ice index eb4ebbf..7f58539 100644 --- a/p2pvr/ice/p2pvr.ice +++ b/p2pvr/ice/p2pvr.ice @@ -7,6 +7,13 @@  module P2PVR {  	["project2:type"] +	class Event extends DVBSI::Event { +		int EventUid; +		bool Current = true; +	}; +	sequence<Event> Events; + +	["project2:type"]  	exception NotFound { };  	// Something that we have recorded. @@ -15,27 +22,23 @@ module P2PVR {  		int RecordingId;  		string StorageAddress;  		string Guid; -		optional(1) int ScheduleId; -		string Title; -		optional(2) string Subtitle; -		optional(3) string Description; -		Common::DateTime StartTime; -		Common::Duration Duration; +		int ScheduleId; +		int EventUid;  	};  	sequence<Recording> RecordingList;  	// Something that defines what we would like to record.  	["project2:type"]  	class Schedule { -		int ScheduleId; +		int ScheduleId = 0;  		optional(1) int ServiceId; -		optional(2) int EventId; +		optional(2) int EventUid;  		optional(3) string Title;  		optional(4) string Search; -		int Priority; +		int Priority = 0;  		Common::Duration Early;  		Common::Duration Late; -		bool Repeats; +		bool Repeats = false;  	};  	sequence<Schedule> ScheduleList; @@ -43,8 +46,7 @@ module P2PVR {  	["project2:type"]  	class ScheduledToRecord {  		int ScheduleId; -		int ServiceId; -		int EventId; +		int EventUid;  	};  	sequence<ScheduledToRecord> ScheduledToRecordList; @@ -93,6 +95,7 @@ module P2PVR {  	};  	sequence<DVBSI::Delivery> Deliveries; +	sequence<int> IntSequence;  	interface SI {  		// Get delivery methods  		idempotent Deliveries GetAllDeliveries(short type); @@ -105,18 +108,19 @@ module P2PVR {  		["project2:rows"]  		idempotent DVBSI::Service GetService(int id) throws NotFound;  		// Get events +		idempotent Events GetEvents(IntSequence eventUids) throws NotFound;  		["project2:rows"] -		idempotent DVBSI::Event GetEvent(int serviceId, int eventId) throws NotFound; +		idempotent Event GetEvent(int serviceId, int eventId) throws NotFound;  		["project2:rows"] -		idempotent DVBSI::Events EventsOnNow(); +		idempotent Events EventsOnNow();  		["project2:rows"] -		idempotent DVBSI::Events EventsInSchedules(); +		idempotent Events EventsInSchedules();  		["project2:rows"] -		idempotent DVBSI::Events EventsInSchedule(int scheduleId); +		idempotent Events EventsInSchedule(int scheduleId);  		["project2:rows"] -		idempotent DVBSI::Events EventsInRange(Common::DateTime from, Common::DateTime to); +		idempotent Events EventsInRange(Common::DateTime from, Common::DateTime to);  		["project2:rows"] -		idempotent DVBSI::Events EventSearch(optional(1) string keywords, optional(2) int serviceId, optional(3) Common::DateTime from, optional(4) Common::DateTime to); +		idempotent Events EventSearch(optional(1) string keywords, optional(2) int serviceId, optional(3) Common::DateTime from, optional(4) Common::DateTime to);  	};  	interface Recorder { diff --git a/p2pvr/lib/containerCreator.h b/p2pvr/lib/containerCreator.h index 9804d9b..289ac9e 100644 --- a/p2pvr/lib/containerCreator.h +++ b/p2pvr/lib/containerCreator.h @@ -19,6 +19,9 @@ class ContainerCreator {  				auto v = P(new V);  				container.push_back(v);  				ObjectRowState<P> rs; +				if (rs.fields.size() != columnCount) { +					throw std::runtime_error("Incorrent column count"); +				}  				for (unsigned int c = 0; c < columnCount; c++) {  					rs.fields[c] = get(c);  				} diff --git a/p2pvr/lib/dvbsiHelpers/event.cpp b/p2pvr/lib/dvbsiHelpers/event.cpp index ca072df..4bca135 100644 --- a/p2pvr/lib/dvbsiHelpers/event.cpp +++ b/p2pvr/lib/dvbsiHelpers/event.cpp @@ -6,30 +6,30 @@ template<>  void  CreateColumns<DVBSI::EventPtr>(const ColumnCreator & cc)  { -			cc("serviceId", true); -			cc("eventId", true); -			cc("title", false); -			cc("titleLang", false); -			cc("subtitle", false); -			cc("description", false); -			cc("descriptionLang", false); -			cc("videoAspect", false); -			cc("videoFrameRate", false); -			cc("videoHd", false); -			cc("audioChannels", false); -			cc("audioLanguage", false); -			cc("subtitleLanguage", false); -			cc("category", false); -			cc("subCategory", false); -			cc("userCategory", false); -			cc("dvbRating", false); -			cc("startTime", false); -			cc("stopTime", false); -			cc("episode", false); -			cc("episodes", false); -			cc("year", false); -			cc("flags", false); -			cc("season", false); +	cc("serviceId", true); +	cc("eventId", true); +	cc("title", false); +	cc("titleLang", false); +	cc("subtitle", false); +	cc("description", false); +	cc("descriptionLang", false); +	cc("videoAspect", false); +	cc("videoFrameRate", false); +	cc("videoHd", false); +	cc("audioChannels", false); +	cc("audioLanguage", false); +	cc("subtitleLanguage", false); +	cc("category", false); +	cc("subCategory", false); +	cc("userCategory", false); +	cc("dvbRating", false); +	cc("startTime", false); +	cc("stopTime", false); +	cc("episode", false); +	cc("episodes", false); +	cc("year", false); +	cc("flags", false); +	cc("season", false);  }  template<> diff --git a/p2pvr/lib/p2pvrHelpers/schedule.cpp b/p2pvr/lib/p2pvrHelpers/schedule.cpp index f8abc1e..91815e9 100644 --- a/p2pvr/lib/p2pvrHelpers/schedule.cpp +++ b/p2pvr/lib/p2pvrHelpers/schedule.cpp @@ -9,7 +9,7 @@ CreateColumns<P2PVR::SchedulePtr>(const ColumnCreator & cc)  {  	cc("scheduleid", true);  	cc("serviceid", true); -	cc("eventid", false); +	cc("eventuid", false);  	cc("title", false);  	cc("search", false);  	cc("priority", false); @@ -24,7 +24,7 @@ BindColumns(RowState & rs, const P2PVR::SchedulePtr & s)  {  	rs.fields[0] << s->ScheduleId;  	rs.fields[1] << s->ServiceId; -	rs.fields[2] << s->EventId; +	rs.fields[2] << s->EventUid;  	rs.fields[3] << s->Title;  	rs.fields[4] << s->Search;  	rs.fields[5] << s->Priority; @@ -39,7 +39,7 @@ UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s)  {  	rs.fields[0] >> s->ScheduleId;  	rs.fields[1] >> s->ServiceId; -	rs.fields[2] >> s->EventId; +	rs.fields[2] >> s->EventUid;  	rs.fields[3] >> s->Title;  	rs.fields[4] >> s->Search;  	rs.fields[5] >> s->Priority;  | 
