1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3
4#include <base/io.h>
5#include <base/logger.h>
6#include <base/net.h>
7#include <base/os.h>
8#include <base/rust.h>
9#include <base/str.h>
10#include <base/time.h>
11
12#include <engine/console.h>
13#include <engine/engine.h>
14#include <engine/shared/config.h>
15#include <engine/shared/jobs.h>
16#include <engine/shared/network.h>
17#include <engine/storage.h>
18
19#include <thread>
20
21class CEngine : public IEngine
22{
23 IConsole *m_pConsole;
24 IStorage *m_pStorage;
25
26 bool m_Logging;
27 std::shared_ptr<CFutureLogger> m_pFutureLogger;
28
29 char m_aAppName[256];
30
31 CJobPool m_JobPool;
32
33 static void Con_DbgLognetwork(IConsole::IResult *pResult, void *pUserData)
34 {
35 CEngine *pEngine = static_cast<CEngine *>(pUserData);
36
37 if(pEngine->m_Logging)
38 {
39 CNetBase::CloseLog();
40 pEngine->m_Logging = false;
41 }
42 else
43 {
44 char aBuf[32];
45 str_timestamp(buffer: aBuf, buffer_size: sizeof(aBuf));
46 char aFilenameSent[IO_MAX_PATH_LENGTH], aFilenameRecv[IO_MAX_PATH_LENGTH];
47 str_format(buffer: aFilenameSent, buffer_size: sizeof(aFilenameSent), format: "dumps/network_sent_%s.txt", aBuf);
48 str_format(buffer: aFilenameRecv, buffer_size: sizeof(aFilenameRecv), format: "dumps/network_recv_%s.txt", aBuf);
49 CNetBase::OpenLog(DataLogSent: pEngine->m_pStorage->OpenFile(pFilename: aFilenameSent, Flags: IOFLAG_WRITE, Type: IStorage::TYPE_SAVE),
50 DataLogRecv: pEngine->m_pStorage->OpenFile(pFilename: aFilenameRecv, Flags: IOFLAG_WRITE, Type: IStorage::TYPE_SAVE));
51 pEngine->m_Logging = true;
52 }
53 }
54
55public:
56 CEngine(bool Test, const char *pAppname, std::shared_ptr<CFutureLogger> pFutureLogger) :
57 m_pFutureLogger(std::move(pFutureLogger))
58 {
59 str_copy(dst&: m_aAppName, src: pAppname);
60 if(!Test)
61 {
62 log_info("engine", "running on %s-%s-%s", CONF_FAMILY_STRING, CONF_PLATFORM_STRING, CONF_ARCH_STRING);
63 log_info("engine", "arch is %s", CONF_ARCH_ENDIAN_STRING);
64
65 char aVersionStr[128];
66 if(os_version_str(version: aVersionStr, length: sizeof(aVersionStr)))
67 {
68 log_info("engine", "operating system version: %s", aVersionStr);
69 }
70
71 rust_panic_use_dbg_assert();
72
73 // init the network
74 net_init();
75 CNetBase::Init();
76 }
77
78#if defined(CONF_PLATFORM_EMSCRIPTEN)
79 // Make sure we don't use more threads than allowed in total (see PTHREAD_POOL_SIZE in Emscripten.toolchain)
80 // otherwise starting more threads may lead to deadlocks as the threads will simply not start.
81 const size_t ThreadCount = 4;
82#else
83 const size_t ThreadCount = std::max(a: 4, b: (int)std::thread::hardware_concurrency()) - 2;
84#endif
85 m_JobPool.Init(NumThreads: ThreadCount);
86
87 m_Logging = false;
88 }
89
90 ~CEngine() override
91 {
92 CNetBase::CloseLog();
93 }
94
95 void Init() override
96 {
97 m_pConsole = Kernel()->RequestInterface<IConsole>();
98 m_pStorage = Kernel()->RequestInterface<IStorage>();
99
100 if(!m_pConsole || !m_pStorage)
101 return;
102
103 m_pConsole->Register(pName: "dbg_lognetwork", pParams: "", Flags: CFGFLAG_SERVER | CFGFLAG_CLIENT, pfnFunc: Con_DbgLognetwork, pUser: this, pHelp: "Log the network");
104 }
105
106 void AddJob(std::shared_ptr<IJob> pJob) override
107 {
108 m_JobPool.Add(pJob: std::move(pJob));
109 }
110
111 void ShutdownJobs() override
112 {
113 m_JobPool.Shutdown();
114 }
115
116 void SetAdditionalLogger(std::shared_ptr<ILogger> &&pLogger) override
117 {
118 m_pFutureLogger->Set(pLogger);
119 }
120};
121
122IEngine *CreateEngine(const char *pAppname, std::shared_ptr<CFutureLogger> pFutureLogger) { return new CEngine(false, pAppname, std::move(pFutureLogger)); }
123IEngine *CreateTestEngine(const char *pAppname) { return new CEngine(true, pAppname, nullptr); }
124