allow a request to be processed in a job
Now we allow a request to be passed into a job queue, and after the job finishes the request is passed into a controller again. In order to achieve this we have a requests queue in System, when we put a request to the job this Request structure is preserved in the queue and for a new request a new Request is added to the queue. while here: - remove App::Lock()/Unlock(), use scoped locking - fix: Plugin now has a Call method which takes ModelConnector and a logger (used in multithreaded environment) - BaseThread has a main_model_connector pointer to the main (from the main thread) model connector - the FastCGI structure fcgi_request moved from App to Request - some methods for handling requests moved from App to Request - small refactoring in main.cpp - add Http class (a http client)
This commit is contained in:
1466
winixd/core/app.cpp
1466
winixd/core/app.cpp
File diff suppressed because it is too large
Load Diff
@@ -74,18 +74,20 @@ public:
|
||||
bool DropPrivileges();
|
||||
void InitLoggers();
|
||||
Log & GetMainLog();
|
||||
void LoadPlugins();
|
||||
bool InitializePlugins();
|
||||
bool Init();
|
||||
bool InitializeRequestForFastCGI();
|
||||
void SetRequestDependency();
|
||||
void InitializeNewRequest();
|
||||
void PrepareRequest();
|
||||
void PutRequestToJob();
|
||||
void Start();
|
||||
void Close();
|
||||
void LogUserGroups();
|
||||
void LogRequestTime();
|
||||
bool Demonize();
|
||||
void SetStopSignal();
|
||||
bool WasStopSignal();
|
||||
bool Lock();
|
||||
void Unlock();
|
||||
Synchro * GetSynchro();
|
||||
void StartThreads();
|
||||
void WaitForThreads();
|
||||
|
||||
@@ -95,10 +97,6 @@ public:
|
||||
// pointers to the current request and a session
|
||||
Cur cur;
|
||||
|
||||
// temporary one request object
|
||||
// current request
|
||||
Request req;
|
||||
|
||||
// users sessions
|
||||
SessionManager session_manager;
|
||||
|
||||
@@ -106,7 +104,8 @@ public:
|
||||
Db db;
|
||||
DbConn db_conn;
|
||||
|
||||
|
||||
// an unique id for each request
|
||||
size_t request_id;
|
||||
|
||||
// ...
|
||||
System system;
|
||||
@@ -136,24 +135,12 @@ private:
|
||||
AcceptBaseParser accept_base_parser;
|
||||
AcceptEncodingParser accept_encoding_parser;
|
||||
Compress compress;
|
||||
FCGX_Request fcgi_request;
|
||||
int fcgi_socket;
|
||||
Synchro synchro;
|
||||
pthread_t signal_thread;
|
||||
std::string socket_to_send_on_exit;
|
||||
std::string send_data_buf;
|
||||
pt::WTextStream json_out_stream;
|
||||
std::string aheader_name, aheader_value;
|
||||
//std::wstring html_filtered;
|
||||
//std::string output_8bit;
|
||||
pt::TextStream serialized_model;
|
||||
pt::WTextStream post_log_tmp_buffer;
|
||||
|
||||
pt::WTextStream output_tmp_filtered_stream;
|
||||
BinaryPage output_8bit;
|
||||
BinaryPage compressed_output;
|
||||
|
||||
std::wstring cookie_id_string;
|
||||
std::wstring http_header_name;
|
||||
std::wstring http_header_value;
|
||||
std::string http_header_8bit;
|
||||
@@ -199,48 +186,15 @@ private:
|
||||
void CheckIfNeedSSLredirect();
|
||||
void SetLocale();
|
||||
void CheckPostRedirect();
|
||||
void UseEzcGenerator();
|
||||
void AddDefaultModels();
|
||||
void SaveSessionsIfNeeded(); // !! IMPROVE ME wywalic do menagera sesji??
|
||||
void LogAccess();
|
||||
void SendData(const BinaryPage & page, FCGX_Stream * out);
|
||||
|
||||
void ReadRequest();
|
||||
|
||||
void SendAnswer();
|
||||
void PrepareRawAnswer();
|
||||
void PrepareJsonAnswer();
|
||||
void PrepareXmlAnswer();
|
||||
void PrepareCsvAnswer();
|
||||
void PrepareContenerizedAnswer();
|
||||
|
||||
void PutSeparatorIfNeeded(bool put_separator);
|
||||
|
||||
void SerializeFieldJson(const wchar_t * field_name);
|
||||
|
||||
void SerializeStream(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeStreamJson(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeStreamXml(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeStreamCsv(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeAllFrames();
|
||||
void SerializeSpecificFrames();
|
||||
void SerializeModels();
|
||||
void Send8bitOutput(BinaryPage & output);
|
||||
|
||||
void SerializeModel(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
void SerializeModelJson(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
void SerializeModelXml(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
void SerializeModelCsv(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
|
||||
void FilterHtmlIfNeeded(const pt::WTextStream & input_stream, BinaryPage & output, bool clear_stream = true);
|
||||
|
||||
|
||||
void LogEnvironmentVariables();
|
||||
void LogEnvironmentHTTPVariables();
|
||||
void ParseAcceptHeader(const wchar_t * header_name, const std::wstring & env, std::vector<HeaderValue> & container, size_t max_len);
|
||||
void ParseAcceptHeader();
|
||||
void ParseAcceptLanguageHeader();
|
||||
|
||||
void SetEnv(const char * name, std::wstring & env);
|
||||
void ReadEnvVariables();
|
||||
void ReadEnvHTTPVariables();
|
||||
@@ -250,37 +204,17 @@ private:
|
||||
void ParsePostJson();
|
||||
void ReadPostJson();
|
||||
void ReadPostVars();
|
||||
|
||||
void CheckIE();
|
||||
void CheckKonqueror();
|
||||
void CheckRequestMethod();
|
||||
void CheckSSL();
|
||||
void CheckHtmx();
|
||||
void SetSubdomain();
|
||||
|
||||
bool IsRequestedFrame();
|
||||
|
||||
void ModifyStatusCodeIfNeeded();
|
||||
void PrepareSessionCookie();
|
||||
void SendHeaders();
|
||||
void SendCookies();
|
||||
bool AddHeader(const wchar_t * name, const wchar_t * value);
|
||||
bool AddHeader(const std::wstring & name, const std::wstring & value);
|
||||
bool AddHeader(const wchar_t * name, const pt::WTextStream & value);
|
||||
bool AddHeader(const std::wstring & name, const pt::WTextStream & value);
|
||||
bool CreateStaticResourcePath(pt::WTextStream & out_path);
|
||||
void PrepareSendFileHeaderForStaticMountpoint();
|
||||
void PrepareHeaderContentType();
|
||||
void ModifyStatusForRedirect();
|
||||
void PrepareSendFileHeader();
|
||||
void PrepareContentEncodingHeader(int compress_encoding);
|
||||
void PrepareContentLengthHeader(size_t output_size);
|
||||
void PrepareHeaderStatus(int http_status);
|
||||
void PrepareHeaders(bool compressing, int compress_encoding, size_t output_size);
|
||||
int SelectDeflateVersion();
|
||||
void SelectCompression(size_t source_len, bool & compression_allowed, int & compression_encoding);
|
||||
bool CanSendContent();
|
||||
void ClearAfterRequest();
|
||||
void IncrementRequestId();
|
||||
|
||||
void LogUser(const char * msg, uid_t id);
|
||||
void LogGroup(const char * msg, gid_t id, bool put_logend = true);
|
||||
@@ -295,6 +229,7 @@ private:
|
||||
|
||||
bool DoDatabaseMigration();
|
||||
bool TryToMakeDatabaseMigration();
|
||||
void WaitForRequestsToFinish();
|
||||
|
||||
|
||||
// !! IMPROVE ME
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2019, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -42,10 +42,11 @@ namespace Winix
|
||||
|
||||
BaseThread::BaseThread() : thread_signal(PTHREAD_COND_INITIALIZER)
|
||||
{
|
||||
synchro = 0;
|
||||
thread_id = 0;
|
||||
work_mode = 0;
|
||||
wake_up_was_called = false;
|
||||
synchro = nullptr;
|
||||
thread_id = 0;
|
||||
work_mode = 0;
|
||||
wake_up_was_called = false;
|
||||
main_model_connector = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +67,12 @@ void BaseThread::set_main_file_log(pt::FileLog * file_log)
|
||||
}
|
||||
|
||||
|
||||
void BaseThread::set_main_model_connector(morm::ModelConnector * main_model_connector)
|
||||
{
|
||||
this->main_model_connector = main_model_connector;
|
||||
}
|
||||
|
||||
|
||||
void BaseThread::Mode(int mode)
|
||||
{
|
||||
work_mode = mode;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2019, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
void set_main_log_buffer(pt::WTextStream * log_buffer);
|
||||
void set_main_file_log(pt::FileLog * file_log);
|
||||
|
||||
void set_main_model_connector(morm::ModelConnector * main_model_connector);
|
||||
|
||||
// work mode
|
||||
// we have two modes:
|
||||
@@ -105,11 +106,13 @@ protected:
|
||||
|
||||
// logger for the main thread
|
||||
Log main_log;
|
||||
// log from WinixBase is meant to be used by the second thread
|
||||
|
||||
// log from WinixBase is meant to be used by the other thread
|
||||
// model connector for the main thread
|
||||
// model_connector from the based class WinixModelDeprecated is meant to be used by the second thread
|
||||
morm::ModelConnector * main_model_connector;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
// signal came (work mode = 0 - default)
|
||||
|
||||
@@ -135,7 +135,7 @@ void Config::AssignValues()
|
||||
fcgi_socket_chmod = Int(L"fcgi_socket_chmod", 0770);
|
||||
fcgi_socket_user = Text(L"fcgi_socket_user");
|
||||
fcgi_socket_group = Text(L"fcgi_socket_group");
|
||||
fcgi_socket_listen = Int(L"fcgi_socket_listen", 100);
|
||||
fcgi_socket_listen = Int(L"fcgi_socket_listen", 1024);
|
||||
log_level = Int(L"log_level", 1);
|
||||
log_request = Int(L"log_request", 1);
|
||||
log_save_each_line = Bool(L"log_save_each_line", false);
|
||||
@@ -344,6 +344,8 @@ void Config::AssignValues()
|
||||
use_antispam_mechanism_for_not_logged_users = Bool(L"use_antispam_mechanism_for_not_logged_users", true);
|
||||
antispam_list_max_size = Size(L"antispam_list_max_size", 10);
|
||||
add_header_cache_no_store_in_htmx_request = Bool(L"add_header_cache_no_store_in_htmx_request", true);
|
||||
|
||||
request_queue_job_limit = Size(L"request_queue_job_limit", 1024);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
bool log_stdout;
|
||||
|
||||
// how many requests should be saved in the same time
|
||||
// if you have a very busy server you can incrase this value
|
||||
// if you have a very busy server you can increase this value
|
||||
// default: 1
|
||||
int log_request;
|
||||
|
||||
@@ -934,7 +934,7 @@ public:
|
||||
// default: X_Real_IP
|
||||
std::wstring proxy_ip_header;
|
||||
|
||||
// use an antismap mechanism for not logged users
|
||||
// use an antispam mechanism for not logged users
|
||||
// when they try to add a new item
|
||||
// default: true
|
||||
bool use_antispam_mechanism_for_not_logged_users;
|
||||
@@ -952,6 +952,13 @@ public:
|
||||
// https://github.com/bigskysoftware/htmx/issues/497
|
||||
bool add_header_cache_no_store_in_htmx_request;
|
||||
|
||||
// a limit for the queue for requests
|
||||
// when a request is scheduled to a job
|
||||
// default: 1024
|
||||
// if the limit is reached then the http status 503 Service Unavailable is returned
|
||||
size_t request_queue_job_limit;
|
||||
|
||||
|
||||
|
||||
|
||||
Config();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2014, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -56,6 +56,14 @@ struct Cur
|
||||
|
||||
// those pointers are never null, if there is no a session for the user
|
||||
// the 'session' pointer pointers at a special temporary session
|
||||
|
||||
Cur()
|
||||
{
|
||||
request = nullptr;
|
||||
session = nullptr;
|
||||
mount = nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -83,6 +83,11 @@ public:
|
||||
static constexpr const wchar_t * text_csv_utf8 = L"text/csv; charset=UTF-8";
|
||||
static constexpr const wchar_t * text_javascript_utf8 = L"text/javascript; charset=UTF-8";
|
||||
|
||||
static constexpr const wchar_t * application_x_www_form_urlencoded = L"application/x-www-form-urlencoded";
|
||||
static constexpr const wchar_t * multipart_form_data = L"multipart/form-data";
|
||||
|
||||
static constexpr const wchar_t * bearer = L"Bearer";
|
||||
|
||||
|
||||
static const int status_200_ok = 200;
|
||||
static const int status_300_multiple_choices = 300;
|
||||
@@ -95,6 +100,7 @@ public:
|
||||
static const int status_404_not_found = 404;
|
||||
static const int status_414_uri_too_long = 414;
|
||||
static const int status_500_internal_server_error = 500;
|
||||
static const int status_503_service_unavailale = 503;
|
||||
|
||||
|
||||
static constexpr const wchar_t * str_status_200 = L"OK";
|
||||
@@ -108,6 +114,7 @@ public:
|
||||
static constexpr const wchar_t * str_status_404 = L"Not Found";
|
||||
static constexpr const wchar_t * str_status_414 = L"URI Too Long";
|
||||
static constexpr const wchar_t * str_status_500 = L"Internal Server Error";
|
||||
static constexpr const wchar_t * str_status_503 = L"Service Unavailable";
|
||||
|
||||
|
||||
static const wchar_t * find_status_string_value(int http_status);
|
||||
@@ -135,6 +142,7 @@ protected:
|
||||
{status_404_not_found, str_status_404},
|
||||
{status_414_uri_too_long, str_status_414},
|
||||
{status_500_internal_server_error, str_status_500},
|
||||
{status_503_service_unavailale, str_status_503},
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2021, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -496,27 +496,27 @@ void Image::ImageSavedCorrectly()
|
||||
}
|
||||
|
||||
log << log3 << "Image: generated a thumbnail: " << dst_path << logend;
|
||||
plugin->Call((Session*)0, WINIX_CREATED_THUMB, &file_work);
|
||||
plugin->Call(model_connector, &log, nullptr, WINIX_CREATED_THUMB, &file_work, nullptr, 0, 0);
|
||||
}
|
||||
else
|
||||
if( item_work.type == WINIX_IMAGE_TYPE_RESIZE )
|
||||
{
|
||||
log << log3 << "Image: image resized: " << dst_path << logend;
|
||||
plugin->Call((Session*)0, WINIX_IMAGE_RESIZED, &file_work);
|
||||
plugin->Call(model_connector, &log, nullptr, WINIX_IMAGE_RESIZED, &file_work, nullptr, 0, 0);
|
||||
}
|
||||
else
|
||||
if( item_work.type == WINIX_IMAGE_TYPE_CROP )
|
||||
{
|
||||
log << log3 << "Image: image cropped: " << dst_path << logend;
|
||||
// !! IMPROVE ME add a correct message
|
||||
//plugin->Call((Session*)0, WINIX_IMAGE_RESIZED, &file_work);
|
||||
//plugin->Call(model_connector, &log, nullptr, WINIX_IMAGE_RESIZED, &file_work, nullptr, 0, 0);
|
||||
}
|
||||
else
|
||||
if( item_work.type == WINIX_IMAGE_TYPE_CROP_THUMB )
|
||||
{
|
||||
log << log3 << "Image: image thumbnail cropped: " << dst_path << logend;
|
||||
// !! IMPROVE ME add a correct message
|
||||
//plugin->Call((Session*)0, WINIX_IMAGE_RESIZED, &file_work);
|
||||
//plugin->Call(model_connector, &log, nullptr, WINIX_IMAGE_RESIZED, &file_work, nullptr, 0, 0);
|
||||
}
|
||||
else
|
||||
if( item_work.type == WINIX_IMAGE_TYPE_CREATE_CROP_NEW_THUMB )
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012-2019, Tomasz Sowa
|
||||
* Copyright (c) 2012-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,6 +35,9 @@
|
||||
#include "job.h"
|
||||
#include "plugin.h"
|
||||
#include "log.h"
|
||||
#include "functions/functions.h"
|
||||
#include "lock.h"
|
||||
|
||||
|
||||
|
||||
namespace Winix
|
||||
@@ -45,31 +48,110 @@ namespace Winix
|
||||
|
||||
Job::Job()
|
||||
{
|
||||
jobs_queue_tab.resize(WINIX_JOBS_HOW_MANY_PRIORITIES);
|
||||
jobs_queue_tab.resize(PRIORITY_HIGHEST + 1);
|
||||
cur = nullptr;
|
||||
functions = nullptr;
|
||||
mounts = nullptr;
|
||||
load_avg = nullptr;
|
||||
req_tab = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Job::CheckPriority(int & priority) const
|
||||
void Job::SetCur(Cur * cur)
|
||||
{
|
||||
if( priority < 0 )
|
||||
priority = 0;
|
||||
this->cur = cur;
|
||||
}
|
||||
|
||||
if( priority >= WINIX_JOBS_HOW_MANY_PRIORITIES )
|
||||
priority = WINIX_JOBS_HOW_MANY_PRIORITIES - 1;
|
||||
|
||||
void Job::SetFunctions(Functions * functions)
|
||||
{
|
||||
this->functions = functions;
|
||||
}
|
||||
|
||||
|
||||
void Job::SetLoadAvg(LoadAvg * load_avg)
|
||||
{
|
||||
this->load_avg = load_avg;
|
||||
}
|
||||
|
||||
|
||||
void Job::SetMounts(Mounts * mounts)
|
||||
{
|
||||
this->mounts = mounts;
|
||||
}
|
||||
|
||||
|
||||
void Job::SetReqTab(std::list<Request> * req_tab)
|
||||
{
|
||||
this->req_tab = req_tab;
|
||||
}
|
||||
|
||||
|
||||
void Job::CheckPriority(size_t & priority) const
|
||||
{
|
||||
if( priority > PRIORITY_HIGHEST )
|
||||
priority = PRIORITY_HIGHEST;
|
||||
}
|
||||
|
||||
|
||||
// first thread (objects locked)
|
||||
void Job::Add(pt::Space & job, int priority)
|
||||
void Job::Add(pt::Space & job, size_t priority)
|
||||
{
|
||||
CheckPriority(priority);
|
||||
jobs_queue_tab[priority].push(job);
|
||||
JobTask task;
|
||||
task.job_type = JobTask::JOB_TYPE_DEFAULT;
|
||||
task.job_id = JobTask::JOB_ID_DEFAULT;
|
||||
task.job = job;
|
||||
jobs_queue_tab[priority].push(task);
|
||||
WakeUpThread();
|
||||
}
|
||||
|
||||
|
||||
// first thread (objects locked)
|
||||
void Job::Add(Request * request, pt::Space & job, size_t priority)
|
||||
{
|
||||
CheckPriority(priority);
|
||||
JobTask task;
|
||||
task.job_type = JobTask::JOB_TYPE_REQUEST_CONTINUATION;
|
||||
task.job_id = JobTask::JOB_ID_DEFAULT;
|
||||
task.request = request;
|
||||
task.job = job;
|
||||
jobs_queue_tab[priority].push(task);
|
||||
WakeUpThread();
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t Job::Size(int priority) const
|
||||
// first thread (objects locked)
|
||||
void Job::Add(long job_id, pt::Space & job, size_t priority)
|
||||
{
|
||||
CheckPriority(priority);
|
||||
JobTask task;
|
||||
task.job_type = JobTask::JOB_TYPE_DEFAULT;
|
||||
task.job_id = job_id;
|
||||
task.job = job;
|
||||
jobs_queue_tab[priority].push(task);
|
||||
WakeUpThread();
|
||||
}
|
||||
|
||||
|
||||
// first thread (objects locked)
|
||||
void Job::Add(long job_id, Request * request, pt::Space & job, size_t priority)
|
||||
{
|
||||
CheckPriority(priority);
|
||||
JobTask task;
|
||||
task.job_type = JobTask::JOB_TYPE_REQUEST_CONTINUATION;
|
||||
task.job_id = job_id;
|
||||
task.request = request;
|
||||
task.job = job;
|
||||
jobs_queue_tab[priority].push(task);
|
||||
WakeUpThread();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
size_t Job::Size(size_t priority) const
|
||||
{
|
||||
CheckPriority(priority);
|
||||
return jobs_queue_tab[priority].size();
|
||||
@@ -81,14 +163,14 @@ size_t Job::Size() const
|
||||
{
|
||||
size_t sum = 0;
|
||||
|
||||
for(size_t i=0 ; i<WINIX_JOBS_HOW_MANY_PRIORITIES ; ++i)
|
||||
for(size_t i=0 ; i <= PRIORITY_HIGHEST ; ++i)
|
||||
sum += Size(i);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
bool Job::Empty(int priority) const
|
||||
bool Job::Empty(size_t priority) const
|
||||
{
|
||||
CheckPriority(priority);
|
||||
return jobs_queue_tab[priority].empty();
|
||||
@@ -97,7 +179,7 @@ bool Job::Empty(int priority) const
|
||||
|
||||
bool Job::Empty() const
|
||||
{
|
||||
for(size_t i=0 ; i<WINIX_JOBS_HOW_MANY_PRIORITIES ; ++i)
|
||||
for(size_t i=0 ; i <= PRIORITY_HIGHEST ; ++i)
|
||||
if( !Empty(i) )
|
||||
return false;
|
||||
|
||||
@@ -121,19 +203,20 @@ bool Job::SignalReceived()
|
||||
// second thread (objects not locked)
|
||||
void Job::Do()
|
||||
{
|
||||
size_t i = WINIX_JOBS_HOW_MANY_PRIORITIES;
|
||||
size_t i = PRIORITY_HIGHEST + 1;
|
||||
bool is_empty;
|
||||
|
||||
while( i-- > 0 && !IsExitSignal() )
|
||||
{
|
||||
do
|
||||
{
|
||||
Lock();
|
||||
is_empty = Empty(i);
|
||||
Unlock();
|
||||
{
|
||||
Winix::Lock lock(synchro);
|
||||
is_empty = Empty(i);
|
||||
}
|
||||
|
||||
if( !is_empty )
|
||||
DoQueue(jobs_queue_tab[i]);
|
||||
DoQueue(jobs_queue_tab[i], i);
|
||||
}
|
||||
while( !is_empty && !IsExitSignal() );
|
||||
}
|
||||
@@ -141,45 +224,144 @@ bool is_empty;
|
||||
|
||||
|
||||
// second thread (objects not locked, jobs_queue is not empty)
|
||||
void Job::DoQueue(JobsQueue & jobs_queue)
|
||||
void Job::DoQueue(JobsQueue & jobs_queue, size_t priority)
|
||||
{
|
||||
bool is_empty;
|
||||
|
||||
do
|
||||
{
|
||||
Lock();
|
||||
// references will not be invalidated after insertion to jobs_queue
|
||||
// (jobs_queue is std::queue and it uses std::deque by default)
|
||||
pt::Space & job = jobs_queue.front();
|
||||
Unlock();
|
||||
JobTask * job_task = nullptr;
|
||||
|
||||
DoJob(job);
|
||||
{
|
||||
Winix::Lock lock(synchro);
|
||||
|
||||
Lock();
|
||||
jobs_queue.pop();
|
||||
is_empty = jobs_queue.empty();
|
||||
Unlock();
|
||||
if( !jobs_queue.empty() )
|
||||
{
|
||||
job_task = &jobs_queue.front();
|
||||
}
|
||||
}
|
||||
|
||||
if( job_task )
|
||||
{
|
||||
DoJob(*job_task, priority);
|
||||
|
||||
{
|
||||
Winix::Lock lock(synchro);
|
||||
|
||||
jobs_queue.pop();
|
||||
is_empty = jobs_queue.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
while( !is_empty && !IsExitSignal() );
|
||||
}
|
||||
|
||||
|
||||
// second thread (objects not locked)
|
||||
void Job::DoJob(pt::Space & job)
|
||||
void Job::DoJob(JobTask & task, size_t priority)
|
||||
{
|
||||
PluginRes res;
|
||||
|
||||
try
|
||||
{
|
||||
PluginRes res = plugin->Call((Session*)0, WINIX_JOB, &job);
|
||||
main_log << logsave;
|
||||
|
||||
if( task.job_type == JobTask::JOB_TYPE_REQUEST_CONTINUATION )
|
||||
{
|
||||
if( task.request )
|
||||
{
|
||||
Cur local_cur;
|
||||
|
||||
// is this correct? we can read the task.request->session ... from the second thread?
|
||||
// chyba tak bo ta struktura zostaje na stosie specjalnie dla joba do uzytku
|
||||
|
||||
local_cur.request = task.request;
|
||||
local_cur.session = task.request->session;
|
||||
local_cur.mount = task.request->mount;
|
||||
cur->request->run_state = Request::RunState::job_run;
|
||||
|
||||
res = plugin->Call(model_connector, &log, &local_cur, WINIX_JOB, &task.job, nullptr, task.job_type, task.job_id);
|
||||
|
||||
{
|
||||
Winix::Lock lock(synchro);
|
||||
cur->request = local_cur.request;
|
||||
cur->session = local_cur.session;
|
||||
cur->mount = local_cur.mount;
|
||||
// winix templates functions uses its own cur (global pointer in TemplatesFunctions namespace)
|
||||
// so we have to set it correctly
|
||||
DoRequestContinuationJob(task, priority);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log << log2 << "Job: request continuation task doesn't have a request set, skipping the job and request continuation" << logend;
|
||||
log << log2 << "Job: this is an internal error, the request if exists in the queue will never be removed" << logend;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = plugin->Call(model_connector, &log, nullptr, WINIX_JOB, &task.job, nullptr, task.job_type, task.job_id);
|
||||
}
|
||||
|
||||
log << logsave;
|
||||
|
||||
if( res.res_true == 0 )
|
||||
DoWinixJob(job);
|
||||
{
|
||||
DoWinixJob(task.job); // probably this will be removed
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
log << log2 << "Job: an exception was catched when doing a job" << logend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// second thread (objects locked)
|
||||
// use main_log (after locking) for the logs to be in the correct order
|
||||
void Job::DoRequestContinuationJob(JobTask & job_task, size_t priority)
|
||||
{
|
||||
if( cur->request->function )
|
||||
{
|
||||
main_log << config->log_delimiter << logend;
|
||||
main_log << log3 << "Job: making a continuation for request " << cur->request << logend;
|
||||
main_log << log4 << "Job: doing directory analysis again" << logend;
|
||||
|
||||
if( functions->ParseOnlyDirs() )
|
||||
{
|
||||
cur->mount = mounts->CalcCurMount(cur->request);
|
||||
cur->request->mount = cur->mount;
|
||||
cur->request->run_state = Request::RunState::job_continuation_run;
|
||||
functions->ContinueMakeFunction();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
main_log << log2 << "Job: request continuation task doesn't have a funtion set, return 500 internal error" << logend;
|
||||
cur->request->http_status = Header::status_500_internal_server_error;
|
||||
}
|
||||
|
||||
if( cur->request->run_state == Request::RunState::assigned_to_job )
|
||||
{
|
||||
log << log3 << "Job: this request (" << cur->request << ") has been moved to the job queue again" << logend;
|
||||
Add(cur->request->job_id, cur->request, cur->request->job, priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
cur->request->FinishRequest(); // jak cur->request->function bedzie null to nie zadzialaja funkcje templajtowe
|
||||
load_avg->StopRequest(cur->request);
|
||||
cur->request->Clear();
|
||||
cur->request->run_state = Request::RunState::finished;
|
||||
RemoveOldRequest(cur->request);
|
||||
}
|
||||
|
||||
main_log << logendrequest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// second thread (objects not locked)
|
||||
void Job::DoWinixJob(pt::Space & job)
|
||||
{
|
||||
@@ -188,6 +370,28 @@ void Job::DoWinixJob(pt::Space & job)
|
||||
|
||||
|
||||
|
||||
// second thread (objects locked)
|
||||
// use main_log for the logs to be in the correct order
|
||||
void Job::RemoveOldRequest(Request * request)
|
||||
{
|
||||
std::list<Request>::iterator i = req_tab->begin();
|
||||
|
||||
while( i != req_tab->end() )
|
||||
{
|
||||
if( &(*i) == request )
|
||||
{
|
||||
main_log << log3 << "Job: removing request " << request << logend;
|
||||
req_tab->erase(i);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Winix
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012-2014, Tomasz Sowa
|
||||
* Copyright (c) 2012-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,22 +32,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef headerfile_winix_core_jobs
|
||||
#define headerfile_winix_core_jobs
|
||||
#ifndef headerfile_winix_core_job
|
||||
#define headerfile_winix_core_job
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include "basethread.h"
|
||||
#include "space/space.h"
|
||||
#include "jobtask.h"
|
||||
#include "cur.h"
|
||||
#include "loadavg.h"
|
||||
#include "mounts.h"
|
||||
|
||||
|
||||
|
||||
namespace Winix
|
||||
{
|
||||
class Functions;
|
||||
|
||||
|
||||
|
||||
#define WINIX_JOBS_HOW_MANY_PRIORITIES 32
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -55,19 +59,35 @@ class Job : public BaseThread
|
||||
{
|
||||
public:
|
||||
|
||||
static const size_t PRIORITY_LOWEST = 0;
|
||||
static const size_t PRIORITY_HIGHEST = 31;
|
||||
|
||||
static const size_t PRIORITY_DEFAULT = 16;
|
||||
static const size_t PRIORITY_REQUEST_CONTINUATION = 17;
|
||||
|
||||
|
||||
Job();
|
||||
|
||||
void SetCur(Cur * cur);
|
||||
void SetFunctions(Functions * functions);
|
||||
void SetLoadAvg(LoadAvg * load_avg);
|
||||
void SetMounts(Mounts * mounts);
|
||||
void SetReqTab(std::list<Request> * req_tab);
|
||||
|
||||
/*
|
||||
add a new job to the queue
|
||||
priority: 0-31 (0 - the lowest priority, 31 - the highest priority)
|
||||
*/
|
||||
void Add(pt::Space & job, int priority = 0);
|
||||
void Add(pt::Space & job, size_t priority = PRIORITY_DEFAULT);
|
||||
void Add(Request * request, pt::Space & job, size_t priority = PRIORITY_DEFAULT);
|
||||
|
||||
void Add(long job_id, pt::Space & job, size_t priority = PRIORITY_DEFAULT);
|
||||
void Add(long job_id, Request * request, pt::Space & job, size_t priority = PRIORITY_DEFAULT);
|
||||
|
||||
/*
|
||||
queue size, and size of all jobs in any priority
|
||||
*/
|
||||
size_t Size(int priority) const;
|
||||
size_t Size(size_t priority) const;
|
||||
size_t Size() const;
|
||||
|
||||
|
||||
@@ -75,17 +95,23 @@ public:
|
||||
true if specified queue is empty
|
||||
or if all queues are empty
|
||||
*/
|
||||
bool Empty(int priority) const;
|
||||
bool Empty(size_t priority) const;
|
||||
bool Empty() const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
typedef std::queue<pt::Space> JobsQueue;
|
||||
Cur * cur;
|
||||
Functions * functions;
|
||||
LoadAvg * load_avg;
|
||||
Mounts * mounts;
|
||||
std::list<Request> * req_tab;
|
||||
|
||||
typedef std::queue<JobTask> JobsQueue;
|
||||
typedef std::vector<JobsQueue> JobsQueueTab;
|
||||
JobsQueueTab jobs_queue_tab;
|
||||
|
||||
void CheckPriority(int & priority) const;
|
||||
void CheckPriority(size_t & priority) const;
|
||||
void SaveToFile();
|
||||
void ReadFromFile();
|
||||
|
||||
@@ -101,9 +127,11 @@ private:
|
||||
|
||||
bool SignalReceived();
|
||||
void Do();
|
||||
void DoQueue(JobsQueue & jobs_queue);
|
||||
void DoJob(pt::Space & job);
|
||||
void DoQueue(JobsQueue & jobs_queue, size_t priority);
|
||||
void DoJob(JobTask & task, size_t priority);
|
||||
void DoRequestContinuationJob(JobTask & job_task, size_t priority);
|
||||
void DoWinixJob(pt::Space & job);
|
||||
void RemoveOldRequest(Request * request);
|
||||
|
||||
};
|
||||
|
||||
|
||||
84
winixd/core/jobtask.h
Normal file
84
winixd/core/jobtask.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is a part of Winix
|
||||
* and is distributed under the 2-Clause BSD licence.
|
||||
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef headerfile_winix_core_jobtask
|
||||
#define headerfile_winix_core_jobtask
|
||||
|
||||
#include "space/space.h"
|
||||
#include "core/request.h"
|
||||
|
||||
|
||||
|
||||
namespace Winix
|
||||
{
|
||||
|
||||
class JobTask
|
||||
{
|
||||
public:
|
||||
|
||||
static const long JOB_TYPE_DEFAULT = 1;
|
||||
static const long JOB_TYPE_REQUEST_CONTINUATION = 2;
|
||||
|
||||
/*
|
||||
* the value of job_id will be defined by each controller
|
||||
* so the default value is better to have -1 instead of for example 1
|
||||
*/
|
||||
static const long JOB_ID_DEFAULT = -1;
|
||||
|
||||
long job_type;
|
||||
long job_id;
|
||||
Request * request;
|
||||
pt::Space job;
|
||||
|
||||
|
||||
JobTask()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
job_type = JOB_TYPE_DEFAULT;
|
||||
job_id = JOB_ID_DEFAULT;
|
||||
request = nullptr;
|
||||
job.clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009-2014, Tomasz Sowa
|
||||
* Copyright (c) 2009-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -43,14 +43,38 @@ namespace Winix
|
||||
|
||||
|
||||
Mount::Mount()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
Mount::Mount(const Mount & m)
|
||||
{
|
||||
operator=(m);
|
||||
}
|
||||
|
||||
|
||||
Mount & Mount::operator=(const Mount & m)
|
||||
{
|
||||
dir_id = m.dir_id;
|
||||
type = m.type;
|
||||
fs = m.fs;
|
||||
param = m.param;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Mount::Clear()
|
||||
{
|
||||
dir_id = -1;
|
||||
type = -1;
|
||||
fs = -1;
|
||||
ClearParams();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Mount::ClearParams()
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009-2014, Tomasz Sowa
|
||||
* Copyright (c) 2009-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -73,6 +73,10 @@ public:
|
||||
|
||||
|
||||
Mount();
|
||||
Mount(const Mount & m);
|
||||
Mount & operator=(const Mount & m);
|
||||
|
||||
void Clear();
|
||||
void ClearParams();
|
||||
|
||||
bool IsPar(int code);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2014, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "mountparser.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "dirs.h"
|
||||
|
||||
|
||||
namespace Winix
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2021, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "mount.h"
|
||||
#include "dirs.h"
|
||||
#include "models/item.h"
|
||||
#include "winixmodeldeprecated.h"
|
||||
|
||||
@@ -49,6 +48,7 @@
|
||||
|
||||
namespace Winix
|
||||
{
|
||||
class Dirs;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009-2021, Tomasz Sowa
|
||||
* Copyright (c) 2009-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "log.h"
|
||||
#include "db/db.h"
|
||||
#include "cur.h"
|
||||
#include "dirs.h"
|
||||
|
||||
|
||||
|
||||
@@ -49,6 +50,7 @@ Mounts::Mounts()
|
||||
{
|
||||
pmount = &empty_mount;
|
||||
skip_static = false;
|
||||
dirs = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +101,7 @@ void Mounts::CreateMounts()
|
||||
CreateMountFs();
|
||||
CreateMountPar();
|
||||
|
||||
plugin->Call((Session*)0, WINIX_ADD_MOUNTS);
|
||||
plugin->Call(WINIX_ADD_MOUNTS);
|
||||
|
||||
empty_mount.param.resize(mount_par_tab.size());
|
||||
empty_mount.ClearParams();
|
||||
@@ -118,12 +120,6 @@ void Mounts::SetDb(Db * pdb)
|
||||
db = pdb;
|
||||
}
|
||||
|
||||
void Mounts::SetCur(Cur * pcur)
|
||||
{
|
||||
cur = pcur;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Mounts::AddMountType(const wchar_t * type)
|
||||
{
|
||||
@@ -221,13 +217,11 @@ void Mounts::ReadMounts(const std::wstring & mounts)
|
||||
|
||||
mount_parser.Parse(mounts, mount_tab);
|
||||
|
||||
CalcCurMount();
|
||||
|
||||
// IMPROVE ME
|
||||
// cur->mount is pointing to the empty mount (it is set in functions.cpp in CheckSpecialFile method)
|
||||
// may would be better to call WINIX_FSTAB_CHANGED after the cur->mount is set?
|
||||
// some plugins are using 'cur' object
|
||||
plugin->Call((Session*)0, WINIX_FSTAB_CHANGED);
|
||||
plugin->Call(WINIX_FSTAB_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +286,7 @@ void Mounts::MountCmsForRoot()
|
||||
|
||||
|
||||
|
||||
Mount * Mounts::CalcCurMount()
|
||||
Mount * Mounts::CalcCurMount(Request * request)
|
||||
{
|
||||
std::vector<Item*>::reverse_iterator i;
|
||||
|
||||
@@ -300,10 +294,10 @@ std::vector<Item*>::reverse_iterator i;
|
||||
|
||||
// when the program starts (when the dir_tab is empty()
|
||||
// we don't want to call MountCmsForRoot()
|
||||
if( cur->request->dir_tab.empty() )
|
||||
if( request->dir_tab.empty() )
|
||||
return pmount;
|
||||
|
||||
for(i = cur->request->dir_tab.rbegin() ; i!=cur->request->dir_tab.rend() ; ++i)
|
||||
for(i = request->dir_tab.rbegin() ; i!=request->dir_tab.rend() ; ++i)
|
||||
{
|
||||
std::map<long, Mount>::iterator m = mount_tab.find( (*i)->id );
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009-2018, Tomasz Sowa
|
||||
* Copyright (c) 2009-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -42,7 +42,6 @@
|
||||
#include <vector>
|
||||
#include "mount.h"
|
||||
#include "error.h"
|
||||
#include "dirs.h"
|
||||
#include "db/db.h"
|
||||
#include "request.h"
|
||||
#include "mountparser.h"
|
||||
@@ -51,7 +50,7 @@
|
||||
|
||||
namespace Winix
|
||||
{
|
||||
|
||||
class Dirs;
|
||||
|
||||
|
||||
|
||||
@@ -115,7 +114,6 @@ public:
|
||||
|
||||
void SetDirs(Dirs * pdirs);
|
||||
void SetDb(Db * pdb);
|
||||
void SetCur(Cur * pcur);
|
||||
|
||||
// dir_id, mount_point
|
||||
typedef std::map<long, Mount> MountTab;
|
||||
@@ -126,7 +124,7 @@ public:
|
||||
void ReadMounts(const std::wstring & mounts);
|
||||
void ReadMounts();
|
||||
|
||||
Mount * CalcCurMount();
|
||||
Mount * CalcCurMount(Request * request);
|
||||
Mount * CalcMount(long dir_id);
|
||||
|
||||
// current mount point
|
||||
@@ -146,7 +144,6 @@ private:
|
||||
|
||||
Db * db;
|
||||
Dirs * dirs;
|
||||
Cur * cur;
|
||||
|
||||
bool skip_static;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2018, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -48,47 +48,6 @@ namespace Winix
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* PluginInfo
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void PluginInfo::set_dependency_for(WinixBase * winix_base)
|
||||
{
|
||||
plugin->SetDependencyFor(winix_base);
|
||||
}
|
||||
|
||||
void PluginInfo::set_dependency_for(WinixBase & winix_base)
|
||||
{
|
||||
set_dependency_for(&winix_base);
|
||||
}
|
||||
|
||||
void PluginInfo::set_dependency_for(WinixModelDeprecated * winix_model)
|
||||
{
|
||||
plugin->SetDependencyFor(winix_model);
|
||||
|
||||
//model_connector = winix_model->get_model_connector();
|
||||
// CHECKME what about model_connector here?
|
||||
}
|
||||
|
||||
void PluginInfo::set_dependency_for(WinixModelDeprecated & winix_model)
|
||||
{
|
||||
set_dependency_for(&winix_model);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Plugin
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void Plugin::UnloadPlugins()
|
||||
{
|
||||
size_t i;
|
||||
@@ -113,6 +72,8 @@ Plugin::Plugin()
|
||||
templates = nullptr;
|
||||
session_manager = nullptr;
|
||||
winix_request = nullptr;
|
||||
|
||||
plugin = this;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,17 +88,6 @@ void Plugin::SetDb(Db * pdb)
|
||||
db = pdb;
|
||||
}
|
||||
|
||||
//void Plugin::SetConfig(Config * pconfig)
|
||||
//{
|
||||
// config = pconfig;
|
||||
//}
|
||||
|
||||
|
||||
void Plugin::SetCur(Cur * pcur)
|
||||
{
|
||||
cur = pcur;
|
||||
}
|
||||
|
||||
|
||||
void Plugin::SetSystem(System * psystem)
|
||||
{
|
||||
@@ -145,6 +95,12 @@ void Plugin::SetSystem(System * psystem)
|
||||
}
|
||||
|
||||
|
||||
void Plugin::SetCur(Cur * cur)
|
||||
{
|
||||
this->cur = cur;
|
||||
}
|
||||
|
||||
|
||||
void Plugin::SetFunctions(Functions * pfunctions)
|
||||
{
|
||||
functions = pfunctions;
|
||||
@@ -157,12 +113,6 @@ void Plugin::SetTemplates(Templates * ptemplates)
|
||||
}
|
||||
|
||||
|
||||
//void Plugin::SetSynchro(Synchro * psynchro)
|
||||
//{
|
||||
// synchro = psynchro;
|
||||
//}
|
||||
|
||||
|
||||
void Plugin::SetSessionManager(SessionManager * psession_manager)
|
||||
{
|
||||
session_manager = psession_manager;
|
||||
@@ -192,10 +142,10 @@ void Plugin::Unlock()
|
||||
|
||||
|
||||
|
||||
bool Plugin::SetDependency(PluginInfo & info)
|
||||
bool Plugin::SetDependencyForPluginInfo(morm::ModelConnector * pmodel_connector, Log * plog, Cur * pcur, PluginInfo & info)
|
||||
{
|
||||
// for safety we call a plugin function only when all our pointers are not null
|
||||
bool res = (db && config && cur && system && functions && templates && synchro && session_manager && winix_request);
|
||||
bool res = (pmodel_connector && plog && pcur && db && config && system && functions && templates && synchro && session_manager && winix_request);
|
||||
|
||||
if( !res )
|
||||
{
|
||||
@@ -204,39 +154,22 @@ bool Plugin::SetDependency(PluginInfo & info)
|
||||
|
||||
info.db = db;
|
||||
info.config = config;
|
||||
info.cur = cur;
|
||||
info.cur = pcur;
|
||||
info.system = system;
|
||||
info.functions = functions;
|
||||
info.templates = templates;
|
||||
info.synchro = synchro;
|
||||
info.session_manager = session_manager;
|
||||
info.plugin = this;
|
||||
info.model_connector = pmodel_connector;;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
* if we call a message from a different thread then a different model connector is needed
|
||||
* (each thread should have its own model connector)
|
||||
*
|
||||
*/
|
||||
info.model_connector = system->get_model_connector();
|
||||
info.log.set_log_buffer(plog->get_log_buffer());
|
||||
info.log.set_file_log(plog->get_file_log());
|
||||
|
||||
info.log.SetDependency(&log);
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void Plugin::SetDependencyFor(WinixBase * winix_base)
|
||||
{
|
||||
winix_base->set_dependency(winix_request);
|
||||
}
|
||||
|
||||
|
||||
void Plugin::SetDependencyFor(WinixModelDeprecated * winix_model)
|
||||
{
|
||||
winix_model->set_dependency(winix_request);
|
||||
}
|
||||
|
||||
|
||||
void Plugin::LoadPlugins(const std::wstring & plugins_dir, const std::vector<std::wstring> & plugins)
|
||||
{
|
||||
@@ -304,7 +237,7 @@ void * plugin_handle;
|
||||
int old_current_plugin;
|
||||
PluginInfo info;
|
||||
|
||||
if( !SetDependency(info) )
|
||||
if( !SetDependencyForPluginInfo(model_connector, &log, cur, info) )
|
||||
return;
|
||||
|
||||
if( !(plugin_handle = LoadInitFun(filename, fun_init)) )
|
||||
@@ -315,6 +248,10 @@ PluginInfo info;
|
||||
current_plugin = (int)plugins.size();
|
||||
info.plugin_id = current_plugin;
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
* all pointers from Cur are null pointers here
|
||||
*/
|
||||
fun_init(info);
|
||||
|
||||
PluginsItem item;
|
||||
@@ -362,19 +299,18 @@ bool Plugin::HasMessage(int message)
|
||||
}
|
||||
|
||||
|
||||
void Plugin::Call(Session * ses, int message, Slots::iterator & slot, PluginInfo & info)
|
||||
void Plugin::Call(morm::ModelConnector * model_connector, Log * plog, Cur * cur, int message, Slots::iterator & slot, PluginInfo & info)
|
||||
{
|
||||
if( !SetDependency(info) )
|
||||
if( !SetDependencyForPluginInfo(model_connector, plog, cur, info) )
|
||||
return;
|
||||
|
||||
current_plugin = slot->second.index;
|
||||
info.plugin_id = current_plugin;
|
||||
info.session = ses;
|
||||
|
||||
if( current_plugin != -1 && ses )
|
||||
info.plugin_data_base = ses->plugin_data.Get(current_plugin);
|
||||
if( current_plugin != -1 && cur->session && !cur->session->is_temporary_session() )
|
||||
info.plugin_data_base = cur->session->plugin_data.Get(current_plugin);
|
||||
else
|
||||
info.plugin_data_base = 0;
|
||||
info.plugin_data_base = nullptr;
|
||||
|
||||
if( !slot->second.is_running )
|
||||
{
|
||||
@@ -411,136 +347,104 @@ void Plugin::Call(Session * ses, int message, Slots::iterator & slot, PluginInfo
|
||||
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, void * p1_, void * p2_, long l1_, long l2_)
|
||||
|
||||
PluginRes Plugin::Call(morm::ModelConnector * model_connector, Log * plog, Cur * cur, int message, void * p1, void * p2, long l1, long l2)
|
||||
{
|
||||
PluginRes res;
|
||||
int old_current_plugin = current_plugin;
|
||||
PluginInfo info;
|
||||
PluginRes res;
|
||||
int old_current_plugin = current_plugin;
|
||||
PluginInfo info;
|
||||
Cur local_cur;
|
||||
|
||||
if( !cur )
|
||||
cur = &local_cur;
|
||||
|
||||
Slots::iterator i = slots.lower_bound(message);
|
||||
|
||||
for( ; i!=slots.end() && i->first==message ; ++i )
|
||||
{
|
||||
info.Clear();
|
||||
info.p1 = p1_;
|
||||
info.p2 = p2_;
|
||||
info.l1 = l1_;
|
||||
info.l2 = l2_;
|
||||
info.p1 = p1;
|
||||
info.p2 = p2;
|
||||
info.l1 = l1;
|
||||
info.l2 = l2;
|
||||
|
||||
Call(ses, message, i, info);
|
||||
Call(model_connector, plog, cur, message, i, info);
|
||||
|
||||
if( info.res )
|
||||
++res.res_true;
|
||||
else
|
||||
++res.res_false;
|
||||
}
|
||||
|
||||
|
||||
current_plugin = old_current_plugin;
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PluginRes Plugin::Call(morm::ModelConnector * model_connector, Log * plog, Session * session, Request * request, Mount * mount, int message, void * p1, void * p2, long l1, long l2)
|
||||
{
|
||||
Cur local_cur;
|
||||
|
||||
local_cur.session = session;
|
||||
local_cur.request = request;
|
||||
local_cur.mount = mount;
|
||||
|
||||
return Call(model_connector, plog, &local_cur, message, p1, p2, l1, l2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message)
|
||||
{
|
||||
return Call(cur->session, message, 0, 0, 0, 0);
|
||||
return Call(model_connector, &log, cur, message, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message, void * p1_)
|
||||
{
|
||||
return Call(cur->session, message, p1_, 0, 0, 0);
|
||||
return Call(model_connector, &log, cur, message, p1_, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message, void * p1_, void * p2_)
|
||||
{
|
||||
return Call(cur->session, message, p1_, p2_, 0, 0);
|
||||
return Call(model_connector, &log, cur, message, p1_, p2_, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message, long l1_)
|
||||
{
|
||||
return Call(cur->session, message, 0, 0, l1_, 0);
|
||||
return Call(model_connector, &log, cur, message, 0, 0, l1_, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message, long l1_, long l2_)
|
||||
{
|
||||
return Call(cur->session, message, 0, 0, l1_, l2_);
|
||||
return Call(model_connector, &log, cur, message, 0, 0, l1_, l2_);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message, void * p1_, long l1_)
|
||||
{
|
||||
return Call(cur->session, message, p1_, 0, l1_, 0);
|
||||
return Call(model_connector, &log, cur, message, p1_, 0, l1_, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message, void * p1_, long l1_, long l2_)
|
||||
{
|
||||
return Call(cur->session, message, p1_, 0, l1_, l2_);
|
||||
return Call(model_connector, &log, cur, message, p1_, 0, l1_, l2_);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(int message, void * p1_, void * p2_, long l1_)
|
||||
{
|
||||
return Call(cur->session, message, p1_, p2_, l1_, 0);
|
||||
return Call(model_connector, &log, cur, message, p1_, p2_, l1_, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message)
|
||||
{
|
||||
return Call(ses, message, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, void * p1_)
|
||||
{
|
||||
return Call(ses, message, p1_, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, void * p1_, void * p2_)
|
||||
{
|
||||
return Call(ses, message, p1_, p2_, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, long l1_)
|
||||
{
|
||||
return Call(ses, message, 0, 0, l1_, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, long l1_, long l2_)
|
||||
{
|
||||
return Call(ses, message, 0, 0, l1_, l2_);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, void * p1_, long l1_)
|
||||
{
|
||||
return Call(ses, message, p1_, 0, l1_, 0);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, void * p1_, long l1_, long l2_)
|
||||
{
|
||||
return Call(ses, message, p1_, 0, l1_, l2_);
|
||||
}
|
||||
|
||||
|
||||
PluginRes Plugin::Call(Session * ses, int message, void * p1_, void * p2_, long l1_)
|
||||
{
|
||||
return Call(ses, message, p1_, p2_, l1_, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
size_t Plugin::Size()
|
||||
{
|
||||
return plugins.size();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2021, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -40,8 +40,10 @@
|
||||
#include <map>
|
||||
#include "pluginmsg.h"
|
||||
#include "plugindata.h"
|
||||
#include "winixbase.h"
|
||||
#include "winixmodeldeprecated.h"
|
||||
#include "modelconnector.h"
|
||||
#include "mount.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -78,6 +80,7 @@ class WinixRequest;
|
||||
|
||||
class Plugin;
|
||||
class Session;
|
||||
class Request;
|
||||
|
||||
|
||||
// move me to a different file
|
||||
@@ -111,14 +114,6 @@ struct PluginInfo
|
||||
|
||||
morm::ModelConnector * model_connector;
|
||||
|
||||
// a session
|
||||
// some messages are sent in a session's context e.g. logging a user
|
||||
// this pointer in not always the same as cur->session, it is preferred
|
||||
// to use this pointer instead of cur->session
|
||||
// (cur->session can point at a temporary object)
|
||||
// this pointer can be null
|
||||
Session * session;
|
||||
|
||||
// pointer to the plugin session (can be null if not set by the plugin or if session is null)
|
||||
// this is taken from session->plugin_data.Get()
|
||||
// you should use WINIX_SESSION_CREATED and WINIX_PLUGIN_SESSION_DATA_REMOVE
|
||||
@@ -130,13 +125,6 @@ struct PluginInfo
|
||||
bool res;
|
||||
|
||||
|
||||
|
||||
void set_dependency_for(WinixBase * winix_base);
|
||||
void set_dependency_for(WinixBase & winix_base);
|
||||
|
||||
void set_dependency_for(WinixModelDeprecated * winix_model);
|
||||
void set_dependency_for(WinixModelDeprecated & winix_model);
|
||||
|
||||
void Clear()
|
||||
{
|
||||
// pointers to winix objects are not cleared here
|
||||
@@ -147,7 +135,6 @@ struct PluginInfo
|
||||
l2 = 0;
|
||||
|
||||
plugin_id = -1;
|
||||
session = 0;
|
||||
plugin_data_base = 0;
|
||||
|
||||
res = false;
|
||||
@@ -173,11 +160,11 @@ struct PluginRes
|
||||
|
||||
|
||||
|
||||
class Plugin : public WinixBase
|
||||
class Plugin : public WinixModelDeprecated
|
||||
{
|
||||
public:
|
||||
|
||||
// index of a plugin which is called by Call() method
|
||||
// index of a plugin which is called by CallAllRegisteredMessages() method
|
||||
// normally: -1
|
||||
int current_plugin;
|
||||
|
||||
@@ -215,12 +202,10 @@ public:
|
||||
~Plugin();
|
||||
|
||||
void SetDb(Db * pdb);
|
||||
//void SetConfig(Config * pconfig);
|
||||
void SetCur(Cur * pcur);
|
||||
void SetSystem(System * psystem);
|
||||
void SetCur(Cur * cur);
|
||||
void SetFunctions(Functions * pfunctions);
|
||||
void SetTemplates(Templates * ptemplates);
|
||||
//void SetSynchro(Synchro * psynchro);
|
||||
void SetSessionManager(SessionManager * psession_manager);
|
||||
|
||||
void SetWinixRequest(WinixRequest * winix_request);
|
||||
@@ -244,16 +229,9 @@ public:
|
||||
PluginRes Call(int message, void * p1_, long l1_);
|
||||
PluginRes Call(int message, void * p1_, long l1_, long l2_);
|
||||
PluginRes Call(int message, void * p1_, void * p2_, long l1_);
|
||||
PluginRes Call(Session * ses, int message, void * p1_, void * p2_, long l1_, long l2_);
|
||||
|
||||
PluginRes Call(Session * ses, int message);
|
||||
PluginRes Call(Session * ses, int message, void * p1_);
|
||||
PluginRes Call(Session * ses, int message, void * p1_, void * p2_);
|
||||
PluginRes Call(Session * ses, int message, long l1_);
|
||||
PluginRes Call(Session * ses, int message, long l1_, long l2_);
|
||||
PluginRes Call(Session * ses, int message, void * p1_, long l1_);
|
||||
PluginRes Call(Session * ses, int message, void * p1_, long l1_, long l2_);
|
||||
PluginRes Call(Session * ses, int message, void * p1_, void * p2_, long l1_);
|
||||
PluginRes Call(morm::ModelConnector * model_connector, Log * plog, Cur * cur, int message, void * p1 = nullptr, void * p2 = nullptr, long l1 = 0, long l2 = 0);
|
||||
PluginRes Call(morm::ModelConnector * model_connector, Log * plog, Session * session, Request * request, Mount * mount, int message, void * p1 = nullptr, void * p2 = nullptr, long l1 = 0, long l2 = 0);
|
||||
|
||||
// how many plugins there are
|
||||
size_t Size();
|
||||
@@ -269,15 +247,13 @@ public:
|
||||
private:
|
||||
|
||||
Db * db;
|
||||
//Config * config;
|
||||
Cur * cur;
|
||||
System * system;
|
||||
Functions * functions;
|
||||
Templates * templates;
|
||||
//Synchro * synchro;
|
||||
SessionManager * session_manager;
|
||||
|
||||
WinixRequest * winix_request;
|
||||
WinixRequest * winix_request; // is it needed anymore? !!!!!!!!!!!!!!!!
|
||||
|
||||
std::wstring temp_path; // used when loading plugins
|
||||
|
||||
@@ -287,11 +263,10 @@ private:
|
||||
Slots slots;
|
||||
|
||||
void * LoadInitFun(const wchar_t * filename, Fun1 & fun_init);
|
||||
void Call(Session * ses, int message, Slots::iterator & slot, PluginInfo & info);
|
||||
void Call(morm::ModelConnector * model_connector, Log * plog, Cur * cur, int message, Slots::iterator & slot, PluginInfo & info);
|
||||
|
||||
bool SetDependency(PluginInfo & info);
|
||||
void SetDependencyFor(WinixBase * winix_base);
|
||||
void SetDependencyFor(WinixModelDeprecated * winix_model);
|
||||
|
||||
bool SetDependencyForPluginInfo(morm::ModelConnector * pmodel_connector, Log * plog, Cur * pcur, PluginInfo & info);
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2021, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -180,6 +180,7 @@ namespace Winix
|
||||
|
||||
// the request is being ended
|
||||
// you can clear some of your objects here
|
||||
// in p1 you have a pointer to the Request object
|
||||
#define WINIX_END_REQUEST 30140
|
||||
|
||||
// a new file (page) has been added
|
||||
@@ -323,6 +324,13 @@ namespace Winix
|
||||
// session is null
|
||||
// if you process the job then return 'true' from the processing method (from plugin call)
|
||||
// so this prevent to make a standard (system) job
|
||||
// in l1 there is a job type (from JobTask structure), e.g. if you want to know whether
|
||||
// the job is a request continuation you should compare l1 == JobTask::JOB_TYPE_REQUEST_CONTINUATION
|
||||
// in l2 there is a job_id - the values passed to the Job::Add(long job_id, ...) method
|
||||
// if you have called Add(...) without long job_id parameter then the default value JobTask::JOB_ID_DEFAULT is used
|
||||
// if the job type is JobTask::JOB_TYPE_REQUEST_CONTINUATION then a pointer to Session can be set,
|
||||
// such a Session has allow_to_delete flag set to false but of course you have to Lock/Unlock when
|
||||
// you are using this structure
|
||||
#define WINIX_JOB 31200
|
||||
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ void PostParser::Parse(FCGX_Stream * in, Request & request)
|
||||
HttpSimpleParser::Parse();
|
||||
|
||||
if( has_winix_raw_post_msg )
|
||||
plugin->Call(0, WINIX_RAW_POST_STRING, &raw_post);
|
||||
plugin->Call(WINIX_RAW_POST_STRING, &raw_post);
|
||||
|
||||
raw_post.clear();
|
||||
}
|
||||
@@ -114,7 +114,7 @@ void PostParser::CreateLog(bool param_added, const std::wstring & name, const st
|
||||
void PostParser::Parameter(std::wstring & name, std::wstring & value)
|
||||
{
|
||||
if( has_winix_post_params_msg )
|
||||
plugin->Call(0, WINIX_POST_PARAMS, &name, &value);
|
||||
plugin->Call(WINIX_POST_PARAMS, &name, &value);
|
||||
|
||||
bool added = request->AddPostVar(name, value);
|
||||
CreateLog(added, name, value);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,6 +51,11 @@
|
||||
#include "models.h"
|
||||
#include "models/winixmodel.h"
|
||||
#include "header.h"
|
||||
#include "compress.h"
|
||||
#include "plugin.h"
|
||||
#include "mount.h"
|
||||
#include "mounts.h"
|
||||
|
||||
|
||||
|
||||
namespace Winix
|
||||
@@ -60,7 +65,7 @@ namespace Winix
|
||||
|
||||
|
||||
class FunctionBase;
|
||||
|
||||
class Templates;
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +92,15 @@ public:
|
||||
*/
|
||||
size_t id;
|
||||
|
||||
// the state of the request
|
||||
// not_assigned - the object is not being used
|
||||
// normal_run - run in the main thread, this state is set after a new request is made
|
||||
// assigned_to_job - the request is preserved and a new job will be called
|
||||
// job_run - run in the job thread (objects are locked)
|
||||
// finished - the request is finished and the object can be removed
|
||||
enum RunState { not_assigned = 0, normal_run, assigned_to_job, job_run, job_continuation_run, finished};
|
||||
|
||||
RunState run_state;
|
||||
|
||||
/*
|
||||
* request start time
|
||||
@@ -230,13 +244,23 @@ public:
|
||||
// null if there is no a function
|
||||
FunctionBase * function;
|
||||
|
||||
// current session (if exists, can be null)
|
||||
Session * session;
|
||||
|
||||
// current mount point (can be null, it is treated as cms filesystem then)
|
||||
Mount * mount;
|
||||
|
||||
// parameters (name:value)
|
||||
ParamTab param_tab;
|
||||
|
||||
// this is a pointer either to the item (if exists) or to the last directory
|
||||
Item * last_item;
|
||||
|
||||
// can we use gzip compression algorithm when sending content to the client
|
||||
bool accept_gzip;
|
||||
|
||||
// can we use deflate compression algorithm when sending content to the client
|
||||
bool accept_deflate;
|
||||
|
||||
|
||||
/*
|
||||
@@ -412,16 +436,24 @@ public:
|
||||
std::vector<Item> item_tab;
|
||||
|
||||
|
||||
/*
|
||||
* FastCGI request structure with pointers to input/output streams
|
||||
*/
|
||||
FCGX_Request fcgi_request;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
long job_id;
|
||||
pt::Space job;
|
||||
|
||||
|
||||
|
||||
Request();
|
||||
void SetConfig(Config * pconfig);
|
||||
|
||||
void SetConfig(Config * config);
|
||||
void SetTemplates(Templates * templates);
|
||||
void SetCompress(Compress * compress);
|
||||
void SetPlugin(Plugin * plugin);
|
||||
void SetMounts(Mounts * mounts);
|
||||
|
||||
|
||||
void fields();
|
||||
@@ -473,10 +505,34 @@ public:
|
||||
bool has_frame(const wchar_t * frame);
|
||||
bool has_frame(const std::wstring & frame);
|
||||
|
||||
void create_job(long job_id);
|
||||
void modify_status_code_if_needed();
|
||||
|
||||
// RENAMEME to add_header_if_not_exists
|
||||
bool AddHeader(const wchar_t * name, const wchar_t * value);
|
||||
bool AddHeader(const std::wstring & name, const std::wstring & value);
|
||||
bool AddHeader(const wchar_t * name, const pt::WTextStream & value);
|
||||
bool AddHeader(const std::wstring & name, const pt::WTextStream & value);
|
||||
|
||||
void FinishRequest();
|
||||
|
||||
private:
|
||||
|
||||
Config * config;
|
||||
Templates * templates;
|
||||
Compress * compress;
|
||||
Plugin * plugin;
|
||||
Mounts * mounts;
|
||||
|
||||
BinaryPage output_8bit;
|
||||
BinaryPage compressed_output;
|
||||
pt::WTextStream output_tmp_filtered_stream;
|
||||
pt::TextStream serialized_model;
|
||||
std::string aheader_name, aheader_value;
|
||||
std::wstring cookie_id_string;
|
||||
std::string send_data_buf;
|
||||
|
||||
|
||||
|
||||
// used in ParamValue() and PostVar() when there is no such a param
|
||||
const std::wstring str_empty;
|
||||
@@ -493,6 +549,45 @@ private:
|
||||
void http_status_error_title(EzcEnv & env);
|
||||
void http_status_error_description(EzcEnv & env);
|
||||
|
||||
void SendAnswer();
|
||||
void PrepareRawAnswer();
|
||||
void PrepareJsonAnswer();
|
||||
void PrepareXmlAnswer();
|
||||
void PrepareCsvAnswer();
|
||||
void PrepareContenerizedAnswer();
|
||||
void PutSeparatorIfNeeded(bool put_separator);
|
||||
void SerializeFieldJson(const wchar_t * field_name);
|
||||
void SerializeStream(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeStreamJson(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeStreamXml(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeStreamCsv(const pt::WTextStream & input_stream, const wchar_t * field_name);
|
||||
void SerializeAllFrames();
|
||||
void SerializeSpecificFrames();
|
||||
void SerializeModels();
|
||||
void SerializeModel(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
void SerializeModelJson(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
void SerializeModelXml(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
void SerializeModelCsv(morm::Wrapper & wrapper, const wchar_t * field_name);
|
||||
void FilterHtmlIfNeeded(const pt::WTextStream & input_stream, BinaryPage & output, bool clear_stream = true);
|
||||
void Send8bitOutput(BinaryPage & output);
|
||||
void SendData(const BinaryPage & page, FCGX_Stream * out);
|
||||
void UseEzcGenerator();
|
||||
int SelectDeflateVersion();
|
||||
void SelectCompression(size_t source_len, bool & compression_allowed, int & compression_encoding);
|
||||
void PrepareSessionCookie();
|
||||
void PrepareHeaders(bool compressing, int compress_encoding, size_t output_size);
|
||||
void ModifyStatusForRedirect();
|
||||
void PrepareSendFileHeaderForStaticMountpoint();
|
||||
void PrepareSendFileHeader();
|
||||
void PrepareContentEncodingHeader(int compress_encoding);
|
||||
void PrepareContentLengthHeader(size_t output_size);
|
||||
void PrepareHeaderContentType();
|
||||
void PrepareHeaderStatus(int http_status);
|
||||
void SendHeaders();
|
||||
void SendCookies();
|
||||
bool CreateStaticResourcePath(pt::WTextStream & out_path);
|
||||
bool CanSendContent();
|
||||
void LogRequestTime();
|
||||
|
||||
MORM_MEMBER_FIELD(Request)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2018, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -97,6 +97,7 @@ void Session::Clear(bool clear_plugin_data)
|
||||
new_session = true;
|
||||
spam_score = 0;
|
||||
remove_me = false;
|
||||
allow_to_delete = true;
|
||||
|
||||
start_time = 0;
|
||||
last_time = 0;
|
||||
@@ -121,6 +122,11 @@ void Session::ClearAfterRequest()
|
||||
}
|
||||
|
||||
|
||||
bool Session::is_temporary_session() const
|
||||
{
|
||||
return id == 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Winix
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2021, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
void ClearAfterRequest();
|
||||
|
||||
|
||||
// 0 - means that there is a temporary session
|
||||
// 0 - means that this is a temporary session
|
||||
long id;
|
||||
|
||||
// a session index
|
||||
@@ -101,10 +101,17 @@ public:
|
||||
bool remember_me;
|
||||
|
||||
|
||||
// if true then this session will be removed by SessionManager
|
||||
// without checking the time expiration
|
||||
// if remove_me is true and if allow_to_delete is true then this session will be
|
||||
// removed by SessionManager without checking the time expiration
|
||||
bool remove_me;
|
||||
|
||||
// if the session can be removed then this value is true (default)
|
||||
// if we continue a request from a controller to a job
|
||||
// then we set this value to false in order for the SessionManager
|
||||
// to not delete this
|
||||
bool allow_to_delete;
|
||||
|
||||
|
||||
PluginData plugin_data;
|
||||
|
||||
|
||||
@@ -133,6 +140,8 @@ public:
|
||||
|
||||
|
||||
|
||||
bool is_temporary_session() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2018, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -82,7 +82,7 @@ Table::iterator i = table.begin();
|
||||
{
|
||||
if( i->plugin_data.HasAllocatedData() )
|
||||
{
|
||||
plugin->Call(&*i, WINIX_PLUGIN_SESSION_DATA_REMOVE); // the session passed here is ok?
|
||||
plugin->Call(model_connector, &log, &*i, nullptr, nullptr, WINIX_PLUGIN_SESSION_DATA_REMOVE, nullptr, nullptr, 0, 0); // the session passed here is ok?
|
||||
}
|
||||
|
||||
//i->plugin_data.DeleteAll(); // it's better to call it here instead in the destructor
|
||||
@@ -116,7 +116,7 @@ IndexId::iterator i = index_id.find(id);
|
||||
|
||||
if( i->second->plugin_data.HasAllocatedData() )
|
||||
{
|
||||
plugin->Call(&*(i->second), WINIX_PLUGIN_SESSION_DATA_REMOVE); // the session passed here is ok?
|
||||
plugin->Call(model_connector, &log, &*(i->second), nullptr, nullptr, WINIX_PLUGIN_SESSION_DATA_REMOVE, nullptr, nullptr, 0, 0); // the session passed here is ok?
|
||||
}
|
||||
|
||||
//i->second->plugin_data.DeleteAll();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2019, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "session.h"
|
||||
#include "sessionparser.h"
|
||||
#include "functions/functionbase.h"
|
||||
#include "system.h"
|
||||
|
||||
|
||||
|
||||
@@ -558,7 +559,7 @@ SessionContainer::Iterator SessionManager::SessionEnd()
|
||||
|
||||
|
||||
|
||||
|
||||
// called from the main thread (from App::Close)
|
||||
void SessionManager::DeleteSessions()
|
||||
{
|
||||
SessionContainer::Iterator i;
|
||||
@@ -567,7 +568,7 @@ void SessionManager::DeleteSessions()
|
||||
{
|
||||
if( i->puser && !i->remember_me )
|
||||
{
|
||||
plugin->Call(&(*i), WINIX_PREPARE_USER_TO_LOGOUT, i->puser);
|
||||
plugin->Call(main_model_connector, &main_log, &(*i), nullptr, nullptr, WINIX_PREPARE_USER_TO_LOGOUT, i->puser, nullptr, 0, 0);
|
||||
last_container->UserLogout(i->puser->id, i->id);
|
||||
}
|
||||
}
|
||||
@@ -599,7 +600,7 @@ SessionContainer::Iterator i = session_tab.FindById(old_id);
|
||||
}
|
||||
|
||||
if( changed )
|
||||
plugin->Call(&(*i), WINIX_SESSION_CHANGED_ID, old_id, new_id);
|
||||
plugin->Call(main_model_connector, &main_log, &(*i), nullptr, nullptr, WINIX_SESSION_CHANGED_ID, nullptr, nullptr, old_id, new_id);
|
||||
else
|
||||
main_log << log1 << "SM: I cannot create a new session id (still uses old one)" << logend;
|
||||
}
|
||||
@@ -612,19 +613,20 @@ return changed;
|
||||
}
|
||||
|
||||
|
||||
// called from the main thread (from App::Init)
|
||||
void SessionManager::InitTmpSession()
|
||||
{
|
||||
Session * old_session = cur->session;
|
||||
|
||||
main_log << log4 << "SM: initializing temporary session" << logend;
|
||||
cur->session = &temporary_session;
|
||||
plugin->Call(WINIX_SESSION_CREATED);
|
||||
plugin->Call(main_model_connector, &main_log, nullptr, WINIX_SESSION_CREATED);
|
||||
|
||||
cur->session = old_session;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// called from the main thread at the and (from App::Close)
|
||||
void SessionManager::UninitTmpSession()
|
||||
{
|
||||
Session * old_session = cur->session;
|
||||
@@ -635,18 +637,16 @@ void SessionManager::UninitTmpSession()
|
||||
|
||||
if( cur->session->plugin_data.HasAllocatedData() )
|
||||
{
|
||||
plugin->Call(cur->session, WINIX_PLUGIN_SESSION_DATA_REMOVE);
|
||||
plugin->Call(main_model_connector, &main_log, cur->session, nullptr, nullptr, WINIX_PLUGIN_SESSION_DATA_REMOVE);
|
||||
}
|
||||
|
||||
//cur->session->plugin_data.DeleteAll(); // this will call plugin.Call(WINIX_PLUGIN_SESSION_DATA_REMOVE);
|
||||
|
||||
cur->session->plugin_data.Resize(0);
|
||||
|
||||
cur->session = old_session;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// called from the main thread (from App::Init)
|
||||
void SessionManager::LoadSessions()
|
||||
{
|
||||
SessionParser sp;
|
||||
@@ -665,7 +665,7 @@ SessionContainer::Iterator i;
|
||||
for(i=session_tab.Begin() ; i != session_tab.End() ; ++i)
|
||||
{
|
||||
i->plugin_data.Resize(plugin->Size());
|
||||
plugin->Call(&(*i), WINIX_SESSION_CREATED);
|
||||
plugin->Call(main_model_connector, &main_log, &(*i), nullptr, nullptr, WINIX_SESSION_CREATED);
|
||||
|
||||
/*
|
||||
!! IMPROVE ME
|
||||
@@ -673,7 +673,7 @@ SessionContainer::Iterator i;
|
||||
*/
|
||||
|
||||
if( i->puser )
|
||||
plugin->Call(&(*i), WINIX_USER_LOGGED);
|
||||
plugin->Call(main_model_connector, &main_log, &(*i), nullptr, nullptr, WINIX_USER_LOGGED);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -758,7 +758,7 @@ size_t SessionManager::MarkAllSessionsToRemove(long user_id)
|
||||
{
|
||||
if( i->puser && i->puser->id == user_id )
|
||||
{
|
||||
plugin->Call(&(*i), WINIX_PREPARE_USER_TO_LOGOUT, i->puser);
|
||||
plugin->Call(main_model_connector, &main_log, &(*i), nullptr, nullptr, WINIX_PREPARE_USER_TO_LOGOUT, i->puser);
|
||||
last_container->UserLogout(i->puser->id, i->id);
|
||||
i->remove_me = true;
|
||||
i->puser = 0;
|
||||
@@ -871,7 +871,7 @@ const int deleted_max_at_once = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( i->remove_me || IsSessionOutdated(*i) )
|
||||
if( i->allow_to_delete && (i->remove_me || IsSessionOutdated(*i)) )
|
||||
{
|
||||
Session * ses = &(*i);
|
||||
++i;
|
||||
@@ -917,16 +917,16 @@ void SessionManager::DeleteSession(Session * del_session)
|
||||
{
|
||||
if( del_session->puser )
|
||||
{
|
||||
plugin->Call(del_session, WINIX_PREPARE_USER_TO_LOGOUT, del_session->puser);
|
||||
plugin->Call(model_connector, &log, del_session, nullptr, nullptr, WINIX_PREPARE_USER_TO_LOGOUT, del_session->puser, nullptr, 0, 0);
|
||||
last_container->UserLogout(del_session->puser->id, del_session->id);
|
||||
del_session->puser = 0;
|
||||
}
|
||||
|
||||
long id = del_session->id;
|
||||
|
||||
plugin->Call(del_session, WINIX_PREPARE_SESSION_TO_REMOVE);
|
||||
plugin->Call(model_connector, &log, del_session, nullptr, nullptr, WINIX_PREPARE_SESSION_TO_REMOVE, del_session->puser, nullptr, 0, 0);
|
||||
session_tab.EraseById(del_session->id);
|
||||
plugin->Call((Session*)0, WINIX_SESSION_REMOVED, id);
|
||||
plugin->Call(model_connector, &log, nullptr, WINIX_SESSION_REMOVED, nullptr, nullptr, id, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2019, Tomasz Sowa
|
||||
* Copyright (c) 2008-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -43,7 +43,6 @@
|
||||
#include "config.h"
|
||||
#include "request.h"
|
||||
#include "lastcontainer.h"
|
||||
#include "system.h"
|
||||
#include "synchro.h"
|
||||
#include "basethread.h"
|
||||
#include "sessionidmanager.h"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2021, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -137,7 +137,6 @@ bool System::Init()
|
||||
mounts.SkipStaticDirs(config->dont_use_static_dirs);
|
||||
mounts.SetDirs(&dirs);
|
||||
mounts.SetDb(db);
|
||||
mounts.SetCur(cur); // only one method is using cur, can be passed as a parameter to the method
|
||||
mounts.CreateMounts();
|
||||
mounts.ReadMounts();
|
||||
|
||||
@@ -168,6 +167,12 @@ bool System::Init()
|
||||
if( !thread_manager.Add(&image, L"image") )
|
||||
return false;
|
||||
|
||||
job.SetCur(cur);
|
||||
job.SetFunctions(functions);
|
||||
job.SetLoadAvg(&load_avg);
|
||||
job.SetMounts(&mounts);
|
||||
job.SetReqTab(&req_tab);
|
||||
|
||||
// SetSynchro will be called by ThreadManager itself
|
||||
// job.ReadFromFile();
|
||||
if( !thread_manager.Add(&job, L"job") )
|
||||
@@ -1440,7 +1445,7 @@ bool System::FollowAllLinks(const std::wstring & link_to,
|
||||
log << log3 << "System: current directory changed and the new file loaded" << logend;
|
||||
}
|
||||
|
||||
mounts.CalcCurMount();
|
||||
mounts.CalcCurMount(cur->request);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1522,5 +1527,28 @@ bool System::AddCommonFileToVar(const wchar_t * file_path, const wchar_t * url,
|
||||
|
||||
|
||||
|
||||
void System::DeleteOldRequests(bool leave_one_object)
|
||||
{
|
||||
std::list<Request>::iterator i = req_tab.begin();
|
||||
|
||||
while( i != req_tab.end() )
|
||||
{
|
||||
// leave at least one object (even if it is finished)
|
||||
if( i->run_state == Request::RunState::finished && (!leave_one_object || req_tab.size() > 1) )
|
||||
{
|
||||
log << log3 << "System: removing finished request " << cur->request << logend;
|
||||
std::list<Request>::iterator old_i = i;
|
||||
++i;
|
||||
req_tab.erase(old_i);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Winix
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2018, Tomasz Sowa
|
||||
* Copyright (c) 2010-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -108,6 +108,9 @@ public:
|
||||
// when winix starts
|
||||
TimeZones time_zones;
|
||||
|
||||
// list of requests, if a request is to be continued in a job then it is preserved in the req_tab
|
||||
// and a new Request is inserted for the next incoming request
|
||||
std::list<Request> req_tab;
|
||||
|
||||
using WinixModelDeprecated::get_model_connector;
|
||||
|
||||
@@ -221,6 +224,7 @@ public:
|
||||
|
||||
void CreateItemLink(const Item & item, std::wstring & link, bool clear_str = true);
|
||||
|
||||
void DeleteOldRequests(bool leave_one_object = false);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2021, Tomasz Sowa
|
||||
* Copyright (c) 2011-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -121,6 +121,7 @@ bool ThreadManager::Add(BaseThread * pbase, const wchar_t * thread_name)
|
||||
data.model_connector.set_winix_time_zones(nullptr); // null for a moment, may will be changed
|
||||
data.model_connector.set_winix_pattern_cacher(nullptr); // null for a moment, may will be changed
|
||||
|
||||
item.object->set_main_model_connector(get_model_connector());
|
||||
item.object->set_model_connector(&data.model_connector);
|
||||
|
||||
if( were_started )
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Tomasz Sowa
|
||||
* Copyright (c) 2018-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -69,7 +69,7 @@ void WinixBase::set_log_buffer(pt::WTextStream * log_buffer)
|
||||
}
|
||||
|
||||
|
||||
void WinixBase::set_file_log(FileLog * file_log)
|
||||
void WinixBase::set_file_log(pt::FileLog * file_log)
|
||||
{
|
||||
log.set_file_log(file_log);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Tomasz Sowa
|
||||
* Copyright (c) 2018-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
void set_config(Config * config);
|
||||
void set_synchro(Synchro * synchro);
|
||||
void set_log_buffer(pt::WTextStream * log_buffer);
|
||||
void set_file_log(FileLog * file_log);
|
||||
void set_file_log(pt::FileLog * file_log);
|
||||
|
||||
Log * get_logger();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Tomasz Sowa
|
||||
* Copyright (c) 2018-2022, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -36,12 +36,16 @@
|
||||
#define headerfile_winix_core_winixmodel
|
||||
|
||||
#include "core/winixbase.h"
|
||||
#include "plugin.h"
|
||||
#include "morm.h"
|
||||
|
||||
|
||||
namespace Winix
|
||||
{
|
||||
/*
|
||||
* Plugin class is based on WinixModelDeprecated so we cannot include plugin.h here
|
||||
*/
|
||||
class Plugin;
|
||||
|
||||
|
||||
// may rename it to WinixConnector or WinixStorage?
|
||||
class WinixModelDeprecated : public WinixBase
|
||||
|
||||
Reference in New Issue
Block a user