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:
2022-07-25 14:21:21 +02:00
parent b2d92b85a0
commit 979ef907fe
65 changed files with 7018 additions and 4437 deletions

View File

@@ -40,20 +40,21 @@
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <curl/curl.h>
#include "core/app.h"
#include "core/version.h"
#include "core/lock.h"
#include "utf8/utf8.h"
#include "mainoptions/mainoptionsparser.h"
#include "pikotools/version.h"
#include "tito.h"
#include "runstatus.h"
namespace Winix
{
/*
application object
*/
@@ -104,6 +105,42 @@ void print_syntax()
RunStatus ParseParameters(int argc, const char ** argv, pt::Space & options)
{
pt::Space arguments;
pt::MainOptionsParser options_parser;
RunStatus run_status;
arguments.add(L"c", 1);
arguments.add(L"config", 1);
pt::MainOptionsParser::Status status = options_parser.parse(argc, argv, options, arguments);
if( status != pt::MainOptionsParser::status_ok )
{
Winix::print_syntax();
run_status.exit_code = RunStatus::EXIT_CODE_PARAMETERS_SYNTAX_ERROR;
run_status.should_continue = false;
}
else
{
if( options.has_key(L"h") || options.has_key(L"help") || options.has_key(L"?") )
{
Winix::print_syntax();
run_status.should_continue = false;
}
if( options.has_key(L"v") || options.has_key(L"version") )
{
Winix::print_version();
run_status.should_continue = false;
}
}
return run_status;
}
void CreateNewDescriptor(int des_dst, int flags)
{
int descriptor;
@@ -278,50 +315,56 @@ bool ReadConfigs(const pt::Space & options, const char ** env)
return status;
}
} // namespace Winix
int main(int argc, const char ** argv, const char ** env)
bool InitCurlLibrary()
{
using Winix::app;
/*
*
* from documentation https://curl.se/libcurl/c/curl_global_init.html
* This function is thread-safe since libcurl 7.84.0 if curl_version_info has the CURL_VERSION_THREADSAFE
* feature bit set (most platforms).
*
* If this is not thread-safe, you must not call this function when any other thread in the program
* (i.e. a thread sharing the same memory) is running. This does not just mean no other thread that
* is using libcurl. Because curl_global_init calls functions of other libraries that are similarly
* thread unsafe, it could conflict with any other thread that uses these other libraries.
*
*/
CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
bool ok = (code == CURLE_OK);
std::srand(std::time(0));
app.system.system_start = time(0);
pt::Space options;
pt::Space arguments;
pt::MainOptionsParser options_parser;
arguments.add(L"c", 1);
arguments.add(L"config", 1);
pt::MainOptionsParser::Status status = options_parser.parse(argc, argv, options, arguments);
if( status != pt::MainOptionsParser::status_ok )
if( !ok )
{
Winix::print_syntax();
return 6;
std::cout << "Cannot initialize curl library, exiting" << std::endl;
}
if( options.has_key(L"h") || options.has_key(L"help") || options.has_key(L"?") )
return ok;
}
void CleanupCurlLibrary()
{
curl_global_cleanup();
}
RunStatus InitializeWinix(Log & log, pt::Space & options, const char ** env)
{
RunStatus run_status;
if( !InitCurlLibrary() )
{
Winix::print_syntax();
return 0;
run_status.exit_code = RunStatus::EXIT_CODE_CANNOT_INITIALIZE_CURL;
run_status.should_continue = false;
return run_status;
}
if( options.has_key(L"v") || options.has_key(L"version") )
if( !ReadConfigs(options, env) )
{
Winix::print_version();
return 0;
}
pt::WTextStream * log_buffer = log.get_log_buffer();
Winix::Log & log = app.GetMainLog();
pt::WTextStream * log_buffer = log.get_log_buffer();
Winix::LogInfo(log, Winix::log3, "UTC booting Winix", true, ""); // date will be printed as UTC because the time zones are not loaded yet
if( !Winix::ReadConfigs(options, env) )
{
// we need to print the buffer by hand because the logger
// is not fully initialized yet
if( log_buffer && !log_buffer->empty() )
@@ -329,21 +372,26 @@ using Winix::app;
pt::wide_stream_to_utf8(*log_buffer, std::cout);
}
return 2;
run_status.exit_code = RunStatus::EXIT_CODE_CANNOT_CORRECTLY_READ_CONFIG;
run_status.should_continue = false;
return run_status;
}
if( options.has_key(L"dump-config") )
{
pt::WTextStream * log_buffer = log.get_log_buffer();
if( log_buffer )
{
log << "all read config options (some of the values could have been modified by winix"
<< " but the modified values are not printed here):" << Winix::logend;
<< " but the modified values are not printed here):" << logend;
app.config.space.serialize_to_space_stream(*log_buffer, true);
log << Winix::logend;
log << logend;
pt::wide_stream_to_utf8(*log_buffer, std::cout);
}
return 0;
run_status.should_continue = false;
return run_status;
}
app.InitLoggers();
@@ -352,55 +400,105 @@ using Winix::app;
app.config.log_stdout = false;
if( !app.config.log_stdout )
Winix::CloseDescriptors();
CloseDescriptors();
if( app.config.demonize && !app.Demonize() )
{
log << Winix::logsave;
return 4;
log << logsave;
run_status.exit_code = RunStatus::EXIT_CODE_CANNOT_DEMONIZE;
run_status.should_continue = false;
return run_status;
}
if( !app.InitFCGI() )
{
log << Winix::logsave;
return 5;
/*
* WARNING:
* when there is a problem with initializing FastCGI FCGX_OpenSocket() will call exit()
* and we never reach here
*/
log << logsave;
run_status.exit_code = RunStatus::EXIT_CODE_CANNOT_INITIALIZE_FASTCGI;
run_status.should_continue = false;
return run_status;
}
if( !app.DropPrivileges() )
{
log << Winix::logsave;
return 3;
log << logsave;
run_status.exit_code = RunStatus::EXIT_CODE_CANNOT_DROP_PRIVILEGES;
run_status.should_continue = false;
return run_status;
}
app.LogUserGroups();
Winix::SavePidFile(log);
SavePidFile(log);
// app.Init() starts other threads as well (they will be waiting on the lock)
if( !app.Init() )
{
Winix::RemovePidFile();
log << Winix::logsave;
return 1;
run_status.exit_code = RunStatus::EXIT_CODE_CANNOT_INITIALIZE_APPLICATION;
run_status.should_continue = false;
return run_status;
}
app.StartThreads();
// now we have more threads, we should use Lock() and Unlock()
// saving all starting logs
app.Lock();
Winix::LogInfo(log, Winix::log1, "Winix", true, "started");
log << Winix::logsave;
app.Unlock();
// main loop
app.Start();
app.Close();
Winix::LogInfo(log, Winix::log1, "Winix", true, "stopped");
Winix::RemovePidFile();
log << Winix::logsave;
return 0;
return run_status;
}
void UninitializeWinix(Log & log)
{
Winix::RemovePidFile();
log << Winix::logsave;
Winix::CleanupCurlLibrary();
}
} // namespace Winix
int main(int argc, const char ** argv, const char ** env)
{
using Winix::app;
Winix::RunStatus run_status;
pt::Space options;
std::srand(std::time(0));
app.system.system_start = time(0);
run_status = Winix::ParseParameters(argc, argv, options);
if( !run_status.should_continue )
return run_status.exit_code;
Winix::Log & log = app.GetMainLog();
Winix::LogInfo(log, Winix::log3, "UTC booting Winix", true, ""); // date will be printed as UTC because the time zones are not loaded yet
run_status = Winix::InitializeWinix(log, options, env);
if( run_status.should_continue )
{
app.StartThreads();
// now we are in multi threaded environment, we should use our locking mechanism
// saving all starting logs (logger can be used without locking)
Winix::LogInfo(log, Winix::log1, "Winix", true, "started");
log << Winix::logsave;
// start the main loop
app.Start();
// close winix
app.Close();
// now all other threads are terminated, we are in single threaded environment again
}
Winix::LogInfo(log, Winix::log1, "Winix", true, "stopped");
UninitializeWinix(log);
return run_status.exit_code;
}

69
winixd/main/runstatus.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* 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_main_runstatus
#define headerfile_winix_main_runstatus
namespace Winix
{
struct RunStatus
{
const static int EXIT_CODE_OK = 0;
const static int EXIT_CODE_CANNOT_INITIALIZE_APPLICATION = 1;
const static int EXIT_CODE_CANNOT_CORRECTLY_READ_CONFIG = 2;
const static int EXIT_CODE_CANNOT_DROP_PRIVILEGES = 3;
const static int EXIT_CODE_CANNOT_DEMONIZE = 4;
const static int EXIT_CODE_CANNOT_INITIALIZE_FASTCGI = 5;
const static int EXIT_CODE_PARAMETERS_SYNTAX_ERROR = 6;
const static int EXIT_CODE_CANNOT_INITIALIZE_CURL = 7;
int exit_code;
bool should_continue;
RunStatus()
{
exit_code = EXIT_CODE_OK;
should_continue = true;
}
};
}
#endif