diff options
-rwxr-xr-x | responsefile.c | 2 | ||||
-rwxr-xr-x | responsevdrdir.c | 1 | ||||
-rwxr-xr-x | smarttvfactory.c | 101 | ||||
-rwxr-xr-x | smarttvfactory.h | 34 | ||||
-rwxr-xr-x | smarttvweb.conf | 3 | ||||
-rwxr-xr-x | stvw_cfg.c | 14 | ||||
-rwxr-xr-x | stvw_cfg.h | 2 |
7 files changed, 147 insertions, 10 deletions
diff --git a/responsefile.c b/responsefile.c index cdf47b4..66fb45f 100755 --- a/responsefile.c +++ b/responsefile.c @@ -23,6 +23,7 @@ #include "responsefile.h" #include "httpresource.h" +#include "smarttvfactory.h" #include <vector> #include <sys/stat.h> @@ -53,6 +54,7 @@ cResponseFile::~cResponseFile() { diff = (now.tv_sec - mResponseStart.tv_sec); diff += (now.tv_usec - mResponseStart.tv_usec) /1000000.0; + (mRequest->mFactory->mUsageStatistics)->addUsageInfo(mRequest->mRemoteAddr, diff); *(mLog->log())<< DEBUGPREFIX << " cResponseFile: Response duration= " << diff << " s" << " RemoteIP= " << mRequest->mRemoteAddr diff --git a/responsevdrdir.c b/responsevdrdir.c index 1813441..5727bd6 100755 --- a/responsevdrdir.c +++ b/responsevdrdir.c @@ -98,6 +98,7 @@ cResponseVdrDir::~cResponseVdrDir() { char f[20]; snprintf(f, sizeof(f), "%.02f", diff); + (mRequest->mFactory->mUsageStatistics)->addUsageInfo(mRequest->mRemoteAddr, diff); *(mLog->log())<< DEBUGPREFIX << " cResponseVdrDir: Response duration= " << f << " s" << " RemoteIP= " << mRequest->mRemoteAddr diff --git a/smarttvfactory.c b/smarttvfactory.c index dc425a5..7afb07d 100755 --- a/smarttvfactory.c +++ b/smarttvfactory.c @@ -1,7 +1,7 @@ /* * smarttvfactory.c: VDR on Smart TV plugin * - * Copyright (C) 2012 - 2014 T. Lohmar + * Copyright (C) 2012 - 2016 T. Lohmar * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -93,7 +93,7 @@ cCmd::cCmd(string t) :mTitle(), mCommand(), mConfirm(false) { void cCmd::trim(string &t) { int m=0; - for (int i=0; i<t.size(); i++) + for (uint i=0; i<t.size(); i++) if (!((t[i] == 32) || (t[i] == 9)) ) { m =i; break; @@ -191,7 +191,6 @@ int cRecEntry::writeXmlItem(string * msg, string own_ip, int own_port) { hdr += "<item>\n"; hdr += "<title>" + mTitle +"</title>\n"; hdr += "<isfolder>false</isfolder>\n"; - // mRec->IsPesRecording(); snprintf(f, sizeof(f), "http://%s:%d%s", own_ip.c_str(), own_port, cUrlEncode::doUrlSaveEncode(mRec->FileName()).c_str()); @@ -360,12 +359,101 @@ cRecFolder* cRecFolder::GetFolder(list<string> *folder_list) { return NULL; } +sUsageStatistics::sUsageStatistics(string fn, Log* l) : collectionDay(), clientEntry(), enabled(true), collectionWindow(3600), + usageStatLogFilename(fn), mLog(l) { + + time_t rawtime; + time (&rawtime); + struct tm * now = localtime (&rawtime); + + now->tm_sec = 0; + collectionDay = mktime(now); + + if (fn.length() == 0) + enabled = false; + + if (enabled) + *(mLog->log()) << mLog->getTimeString() + << ": UsageStats is enabled, StatsFile= " + << usageStatLogFilename + << " collectionWindow=" << collectionWindow + << endl; + else + *(mLog->log()) << mLog->getTimeString() + << ": UsageStats is disabled " + << endl; +}; + +void sUsageStatistics::checkDay() { + time_t rawtime; + struct tm * now; + + time (&rawtime); + now = localtime (&rawtime); + + if ((collectionDay + collectionWindow ) > rawtime) { + *(mLog->log()) << mLog->getTimeString() + << ": UsageStats - check: Still not time to write time left= " + << (collectionDay + collectionWindow ) - rawtime + << endl; + return; + } + + ofstream ofs; + ofs.open(usageStatLogFilename.c_str(), ios::out | ios::app); + + *(mLog->log()) << mLog->getTimeString() + << ": UsageStats: appending " << clientEntry.size() << " entries to log" << endl; + now->tm_sec = 0; + + for (uint i = 0; i < clientEntry.size(); i++) { + ofs << mLog->getTimeString() << " client " << clientEntry[i].ipAddr + << " Dur= " << clientEntry[i].usage + << " sec Count= " << clientEntry[i].count + << endl; + } + + ofs.close(); + + while (collectionDay < rawtime) { + collectionDay += collectionWindow; + } + + // Flush and reset + clientEntry.clear(); +} + +void sUsageStatistics::addUsageInfo (string ip, double dur) { + if (!enabled) + return; + + checkDay(); + + bool found = false; + for (uint i = 0; i < clientEntry.size(); i++) { + if (clientEntry[i].ipAddr == ip) { + found = true; + clientEntry[i].usage += dur; + clientEntry[i].count += 1; + *(mLog->log()) << mLog->getTimeString() + << ": UsageStats: adding info for " << ip << " dur= " << dur << " sec to existing record" << endl; + break; + } + } + if (!found) { + sUsageStatsEntry elm (ip, dur); + *(mLog->log()) << mLog->getTimeString() + << ": UsageStats: adding info for " << ip << " dur= " << dur << " sec to a new record" << endl; + clientEntry.push_back(sUsageStatsEntry(ip, dur)); + } +} SmartTvServer::SmartTvServer(): cStatus(), mRequestCount(0), isInited(false), serverPort(PORT), mServerFd(-1), mSegmentDuration(10), mHasMinBufferTime(40), mLiveChannels(20), clientList(), mConTvClients(), mRecCmds(), mCmdCmds(), mRecMsg(), mCmdMsg(), mActiveSessions(0), mHttpClientId(0), mConfig(NULL), mMaxFd(0), - mManagedUrls(NULL), mActRecordings(), mRecordings(NULL), mRecState(0), mClientBlackList() { + mManagedUrls(NULL), mActRecordings(), mRecordings(NULL), mRecState(0), mClientBlackList(), + mUsageStatistics(NULL){ } @@ -399,7 +487,7 @@ void SmartTvServer::Recording(const cDevice *Device, const char *Name, const cha *(mLog.log()) << mLog.getTimeString() << ": WARNING in SmartTvServer::Recording: Name and FileName are NULL. Return. " << endl; return; } - // cRecording* rec = Recordings.GetByName(FileName); + #if APIVERSNUM > 20300 LOCK_RECORDINGS_READ; const cRecording* rec = Recordings->GetByName(FileName); @@ -1116,6 +1204,9 @@ void SmartTvServer::initServer(string dir, cSmartTvConfig* cfg) { mHasMinBufferTime= mConfig->getHasMinBufferTime(); mLiveChannels = mConfig->getLiveChannels(); + //mUsageStatistics = new sUsageStatistics("/multimedia/video/usage.txt", &mLog); + mUsageStatistics = new sUsageStatistics(mConfig->getUsageStatsLogFile(), &mLog); + *(mLog.log()) << mLog.getTimeString() <<": HTTP server listening on port " << serverPort << endl; mServerFd = socket(PF_INET, SOCK_STREAM, 0); diff --git a/smarttvfactory.h b/smarttvfactory.h index 3e5b95b..c4699e1 100755 --- a/smarttvfactory.h +++ b/smarttvfactory.h @@ -1,7 +1,7 @@ /* * smarttvfactory.h: VDR on Smart TV plugin * - * Copyright (C) 2012 - 2015 T. Lohmar + * Copyright (C) 2012 - 2016 T. Lohmar * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -47,8 +47,8 @@ class cStatus { using namespace std; -#define PLG_VERSION "1.0.3" -#define SERVER "SmartTvWeb/1.0.3" +#define PLG_VERSION "1.0.4" +#define SERVER "SmartTvWeb/1.0.4" class cLiveRelay; @@ -146,6 +146,32 @@ class cRecEntry : public cRecEntryBase { }; }; +//---------------------------- +struct sUsageStatsEntry { + string ipAddr; + double usage; + int count; +sUsageStatsEntry() : ipAddr(""), usage(0.0), count (0) {}; +sUsageStatsEntry(string ip, double d) : ipAddr(ip), usage(d), count(1) {}; +}; + +class sUsageStatistics { + private: + // struct tm collectionDay; // once the collectionDay is changed, the stats are written + time_t collectionDay; // once the collectionDay is changed, the stats are written + vector<sUsageStatsEntry> clientEntry; + bool enabled; + int collectionWindow; + + string usageStatLogFilename; + Log *mLog; + + void checkDay(); + + public: + sUsageStatistics(string fn, Log* mLog); + void addUsageInfo (string ip, double dur); +}; class SmartTvServer : public cStatus { @@ -264,6 +290,8 @@ class SmartTvServer : public cStatus { void CreateRecDb(); list<string> mClientBlackList; + public: + sUsageStatistics *mUsageStatistics; }; diff --git a/smarttvweb.conf b/smarttvweb.conf index 97849ec..9f08201 100755 --- a/smarttvweb.conf +++ b/smarttvweb.conf @@ -44,3 +44,6 @@ BuiltInLiveBufDur 600 # Value of the access-control-allow-origin HTTP response header #CorsHeader http://192.168.1.122 http://teefax:8000 +# Allows collecting of usage stats of recording +# Intention is to allow parents to monitor TV recordings consumption +# UsageStatsLogFile /var/log/smarttvweb/usagestats.log
\ No newline at end of file @@ -1,7 +1,7 @@ /* * stvw_cfg.h: VDR on Smart TV plugin * - * Copyright (C) 2012, 2013 T. Lohmar + * Copyright (C) 2012 - 2016 T. Lohmar * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -35,7 +35,7 @@ cSmartTvConfig::cSmartTvConfig(): mConfigDir(""), mLog(NULL), mCfgFile(NULL), mU mLogFile(), mMediaFolder(), mSegmentDuration(), mHasMinBufferTime(), mHasBitrateCorrection(), mLiveChannels(), mGroupSep(IGNORE), mServerAddress(""), mServerPort(8000), mCmds(false), mUseStreamDev4Live(true), mBuiltInLiveStartMode (4), mBuiltInLivePktBuf4Hd(150), mBuiltInLivePktBuf4Sd(75), mBuiltInLiveBufDur(0.6), - mAddCorsHeader(false), mCorsHeaderPyld() { + mAddCorsHeader(false), mCorsHeaderPyld(), mUsageStatsLogFile("") { #ifndef STANDALONE mLogFile= ""; @@ -79,6 +79,8 @@ void cSmartTvConfig::Store(cPlugin *mPlugin) { mPlugin->SetupStore("CorsHeader", mCorsHeaderPyld.c_str()); else mPlugin->SetupStore("CorsHeader"); + if (mUsageStatsLogFile.length() != 0) + mPlugin->SetupStore("UsageStatsLogFile", mUsageStatsLogFile.c_str()); } bool cSmartTvConfig::SetupParse(const char *name, const char *value) { @@ -125,6 +127,9 @@ bool cSmartTvConfig::SetupParse(const char *name, const char *value) { mAddCorsHeader = true; mCorsHeaderPyld = value; } + else if (strcmp(name, "UsageStatsLogFile") == 0) { + mUsageStatsLogFile = value; + } else return false; @@ -303,6 +308,11 @@ void cSmartTvConfig::readConfig() { mCorsHeaderPyld = value; continue; } + + if (strcmp(attr, "UsageStatsLogFile") == 0) { + mUsageStatsLogFile = value; + continue; + } #ifndef STANDALONE esyslog("WARNING in SmartTvWeb: Attribute= %s with value= %s was not processed, thus ignored.", attr, value); @@ -97,6 +97,7 @@ class cSmartTvConfig { bool mAddCorsHeader; string mCorsHeaderPyld; + string mUsageStatsLogFile; // cPlugin* mPlugin; cWidgetConfigBase mWidgetConfigBase; public: @@ -131,6 +132,7 @@ class cSmartTvConfig { bool addCorsHeader() { return mAddCorsHeader; }; string getCorsHeader() {return mCorsHeaderPyld; }; + string getUsageStatsLogFile() { return mUsageStatsLogFile; }; string GetWidgetConf() { return mWidgetConfigBase.GetWidgetConf(); }; }; |