/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2010-2018, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "core/log.h" #include "core/request.h" #include "core/config.h" #include "db/db.h" #include "core/cur.h" #include "bot.h" #include "stats.h" #include "templates.h" #include "statssession.h" namespace Winix { extern "C" void Init(PluginInfo &); static const wchar_t plugin_name[] = L"stats"; // if there is a winix function parameter nostat_param used // such as: http://mysite.com/uptime/nostat // then the statistics will not be calculated // and winix will not log about creating and destroying plugins date // (useful when making performance tests so it not change the real statistics) static const wchar_t nostat_param[] = L"nostat"; namespace Stats { Stats stats; Bot bot; long current_item_id; void CalcItemId(Cur * cur) { if( cur->request->is_item ) current_item_id = cur->request->item.id; else if( !cur->request->dir_tab.empty() ) current_item_id = cur->request->dir_tab.back()->id; else current_item_id = -1; } void UpdateStats(PluginInfo & info, Stats::ItemStats & item_stats) { bot.SetBrowserName(info.cur->request->env_http_user_agent); stats.global_all += 1; item_stats.all += 1; if( bot.IsGoogle() ) { stats.global_google += 1; item_stats.google += 1; } if( bot.IsYahoo() ) { stats.global_yahoo += 1; item_stats.yahoo += 1; } if( bot.IsBing() ) { stats.global_bing += 1; item_stats.bing += 1; } } void ContentMake(PluginInfo & info) { StatsSession * stats_session = 0; CalcItemId(info.cur); if( current_item_id == - 1 || !info.plugin_data_base ) return; stats_session = reinterpret_cast(info.plugin_data_base); stats_session->nostat = info.cur->request->IsParam(nostat_param); if( stats_session->nostat ) return; // this simply prevents F5 (refresh) from a webbrowser if( stats_session->last_visited != -1 && stats_session->last_visited == current_item_id ) return; stats_session->last_visited = current_item_id; UpdateStats(info, stats.stats_tab[current_item_id]); if( !stats_session->calculated ) { stats.global_unique += 1; stats_session->calculated = true; } stats.PeriodicSave(); } void SessionCreated(PluginInfo & info) { StatsSession * d = new StatsSession(); info.session->plugin_data.Assign(info.plugin->current_plugin, d); if( !info.cur->request->IsParam(nostat_param) ) { info.log << log4 << "Stats: created stats plugin data" << ", plugin id: " << info.plugin_id << ", pointer: " << d << logend; } } void RemoveSession(PluginInfo & info) { if( !info.plugin_data_base ) { // temporarily for debug // sometimes the pointer is null here info.log << log1 << "Stats: why the info.plugin_data_base is zero? !!!!, ses_id: " << info.session->id << logend; return; } StatsSession * d = reinterpret_cast(info.plugin_data_base); if( !d->nostat ) { info.log << log4 << "Stats: deleting stats plugin data" << ", plugin id: " << info.plugin_id << ", pointer: " << info.plugin_data_base << logend; } delete info.plugin_data_base; } void Close(PluginInfo & info) { stats.SaveStats(); } void RemoveFile(PluginInfo & info) { const Item * item = reinterpret_cast(info.p1); if( item ) stats.RemoveItem(item->id); } void RemoveDir(PluginInfo & info) { const Item * item = reinterpret_cast(info.p1); if( item ) stats.RemoveItem(item->id); } } // namespace void Init(PluginInfo & info) { using namespace Stats; info.plugin->Assign(WINIX_TEMPLATES_CREATEFUNCTIONS, CreateFunctions); info.plugin->Assign(WINIX_CONTENT_MAKE, ContentMake); info.plugin->Assign(WINIX_SESSION_CREATED, SessionCreated); info.plugin->Assign(WINIX_PLUGIN_SESSION_DATA_REMOVE, RemoveSession); info.plugin->Assign(WINIX_PREPARE_TO_CLOSE, Close); info.plugin->Assign(WINIX_FILE_REMOVED, RemoveFile); info.plugin->Assign(WINIX_DIR_PREPARE_TO_REMOVE, RemoveDir); info.set_dependency_for(stats); stats.ReadConfig(info.config); stats.ReadStats(); info.p1 = (void*)plugin_name; } } // namespace Winix