Skip to content

Commit

Permalink
new year first update
Browse files Browse the repository at this point in the history
  • Loading branch information
AstroAir committed Feb 9, 2024
1 parent 7c3ce99 commit 344f931
Show file tree
Hide file tree
Showing 38 changed files with 1,502 additions and 309 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/windows-mingw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3

- name: Get submodules
run: git submodule init && git submodule update

- name: Build INDI Core
run: |
mkdir build
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Lithium
## Lithium

<p align="center">
<img src="https://img.shields.io/badge/dialect-C%2B%2B20-blue">
Expand All @@ -10,6 +10,9 @@
</p>

[![Codacy Badge](https://app.codacy.com/project/badge/Grade/d3fed47a38e642a390d8ee506dc0acb3)](https://app.codacy.com/gh/ElementAstro/Lithium/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=ElementAstro_Lithium&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=ElementAstro_Lithium&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=ElementAstro_Lithium&metric=bugs)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)

## Introduction

Expand Down Expand Up @@ -130,7 +133,7 @@ Let us nurture a heart that yearns for wisdom and grace,
And never lose sight of this noble race.
```

#
##

## 简介

Expand Down
4 changes: 2 additions & 2 deletions locale/lithium.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: [email protected]\n"
"POT-Creation-Date: 2024-02-06 04:56+0800\n"
"POT-Creation-Date: 2024-02-06 17:50+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand All @@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#: E:/msys64/home/Lithium/src/LithiumApp.cpp:549
#: E:/msys64/home/Lithium/src/LithiumApp.cpp:551
#, c++-format
msgid "Dispatched command {} with result: {}"
msgstr ""
2 changes: 1 addition & 1 deletion locale/po/en_US.UTF-8/lithium.po
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#: E:/msys64/home/Lithium/src/LithiumApp.cpp:549
#: E:/msys64/home/Lithium/src/LithiumApp.cpp:551
#, c++-format
msgid "Dispatched command {} with result: {}"
msgstr ""
2 changes: 2 additions & 0 deletions src/LithiumApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ namespace Lithium
m_ProcessManager = GetPtr<Atom::System::ProcessManager>("lithium.system.process");
m_MessageBus = GetPtr<Atom::Server::MessageBus>("lithium.bus");

m_TaskManager = GetPtr<TaskManager>("lithium.task.manager");

// Common Message Processing Threads
// Max : Maybe we only need one thread for Message, and dynamically cast message
// to the right type to process.
Expand Down
2 changes: 1 addition & 1 deletion src/addon/loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace Lithium
* @param dir_name 模块所在的目录名称。
* @param threadManager 线程管理器的共享指针。
*/
ModuleLoader(const std::string &dir_name);
explicit ModuleLoader(const std::string &dir_name);

/**
* @brief 析构函数,释放 ModuleLoader 对象。
Expand Down
2 changes: 1 addition & 1 deletion src/addon/manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ constexpr std::string DYNAMIC_LIBRARY_EXTENSION = ".so";

namespace Lithium
{
ComponentManager::ComponentManager()
ComponentManager::ComponentManager() : m_ModuleLoader(nullptr), m_Env(nullptr), m_ComponentFinder(nullptr), m_Sandbox(nullptr), m_Compiler(nullptr)
{
m_ModuleLoader = GetPtr<Lithium::ModuleLoader>("lithium.addon.loader");
m_Env = GetPtr<Atom::Utils::Env>("lithium.utils.env");
Expand Down
4 changes: 1 addition & 3 deletions src/addon/module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ namespace Lithium
void *address;
std::vector<std::string> parameters;

FunctionInfo()
FunctionInfo() : name(""), address(nullptr)
{
name = "";
address = nullptr;
}
};

Expand Down
22 changes: 22 additions & 0 deletions src/atom/async/async.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,28 @@ namespace Atom::Async
private:
std::vector<std::shared_ptr<AsyncWorker<ResultType>>> workers_; ///< The list of managed AsyncWorker instances.
};

/**
* @brief Async execution with retry.
*
* @tparam Func The type of the function to be executed asynchronously.
* @tparam Args The types of the arguments to be passed to the function.
* @param func The function to be executed asynchronously.
* @param args The arguments to be passed to the function.
* @return A shared pointer to the created AsyncWorker instance.
*/
template <typename Func, typename... Args>
std::future<decltype(std::declval<Func>()(std::declval<Args>()...))> asyncRetry(Func &&func, int attemptsLeft, std::chrono::milliseconds delay, Args &&...args);

/**
* @brief Gets the result of the task with a timeout.
*
* @param future The future representing the asynchronous task.
* @param timeout The timeout duration.
* @return The result of the task.
*/
template <typename ReturnType>
ReturnType getWithTimeout(std::future<ReturnType> &future, std::chrono::milliseconds timeout);
}

#include "async_impl.hpp"
Expand Down
55 changes: 53 additions & 2 deletions src/atom/async/async_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Atom::Async
}

template <typename ResultType>
ResultType AsyncWorker<ResultType>::GetResult()
[[nodiscard]] ResultType AsyncWorker<ResultType>::GetResult()
{
if (!task_.valid())
{
Expand Down Expand Up @@ -110,7 +110,7 @@ namespace Atom::Async

template <typename ResultType>
template <typename Func, typename... Args>
std::shared_ptr<AsyncWorker<ResultType>> AsyncWorkerManager<ResultType>::CreateWorker(Func &&func, Args &&...args)
[[nodiscard]] std::shared_ptr<AsyncWorker<ResultType>> AsyncWorkerManager<ResultType>::CreateWorker(Func &&func, Args &&...args)
{
auto worker = std::make_shared<AsyncWorker<ResultType>>();
workers_.push_back(worker);
Expand Down Expand Up @@ -154,6 +154,57 @@ namespace Atom::Async
{
worker->Cancel();
}

template <typename Func, typename... Args>
[[nodiscard]] std::future<decltype(std::declval<Func>()(std::declval<Args>()...))> asyncRetry(Func &&func, int attemptsLeft, std::chrono::milliseconds delay, Args &&...args)
{
static_assert(std::is_void<decltype(std::declval<Func>()(std::declval<Args>()...))>::value == false, "Func must return a value");

if (attemptsLeft <= 1)
{
// 最后一次尝试,直接执行
return std::async(std::launch::deferred, std::forward<Func>(func), std::forward<Args>(args)...);
}

// 尝试执行函数
auto attempt = std::async(std::launch::async, std::forward<Func>(func), std::forward<Args>(args)...);

try
{
// 立即获取结果,如果有异常会在这里抛出
auto result = attempt.get();
// 如果成功,则直接返回一个已经有结果的 future
return std::async(std::launch::deferred, [result]() -> decltype(func(args...))
{ return result; });
}
catch (...)
{
if (attemptsLeft <= 1)
{
// 所有尝试都失败,重新抛出最后一次的异常
throw;
}
else
{
// 等待一段时间后重试
std::this_thread::sleep_for(delay);
return asyncRetry(std::forward<Func>(func), attemptsLeft - 1, delay, std::forward<Args>(args)...);
}
}
}

template <typename ReturnType>
ReturnType getWithTimeout(std::future<ReturnType> &future, std::chrono::milliseconds timeout)
{
if (future.wait_for(timeout) == std::future_status::ready)
{
return future.get();
}
else
{
throw std::runtime_error("Timeout occurred while waiting for future result");
}
}
} // namespace Atom::Async

#endif
2 changes: 1 addition & 1 deletion src/atom/connection/shared_memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ namespace Atom::Connection
* @param create 是否创建新的共享内存
*/
template <typename T>
SharedMemory(const std::string &name, bool create = true);
explicit SharedMemory(const std::string &name, bool create = true);

/**
* @brief 析构函数,释放共享内存
Expand Down
8 changes: 4 additions & 4 deletions src/atom/connection/udp_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ namespace Atom::Connection
return;
}

if (bind(m_serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
if (bind(m_serverSocket, reinterpret_cast<struct sockaddr *>(&serverAddr), sizeof(serverAddr)) == SOCKET_ERROR)
{
LOG_F(ERROR, "Bind failed with error.");
closesocket(m_serverSocket);
Expand Down Expand Up @@ -117,8 +117,8 @@ namespace Atom::Connection
targetAddr.sin_port = htons(port);
inet_pton(AF_INET, ip.c_str(), &targetAddr.sin_addr);

int sentBytes = sendto(m_serverSocket, message.c_str(), message.length(), 0,
(struct sockaddr *)&targetAddr, sizeof(targetAddr));
int sentBytes = sendto(m_serverSocket, message.c_str(), static_cast<int>(message.length()), 0,
reinterpret_cast<struct sockaddr *>(&targetAddr), sizeof(targetAddr));
if (sentBytes == SOCKET_ERROR)
{
LOG_F(ERROR, "Failed to send message.");
Expand All @@ -139,7 +139,7 @@ namespace Atom::Connection
while (m_running.load())
{
int bytesReceived = recvfrom(m_serverSocket, buffer, sizeof(buffer), 0,
(struct sockaddr *)&clientAddr, &clientAddrSize);
reinterpret_cast<struct sockaddr *>(&clientAddr), &clientAddrSize);
if (bytesReceived == SOCKET_ERROR)
{
LOG_F(ERROR, "recvfrom failed with error.");
Expand Down
151 changes: 151 additions & 0 deletions src/atom/system/command.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* command.cpp
*
* Copyright (C) 2023-2024 Max Qian <lightapt.com>
*/

/*************************************************
Date: 2023-12-24
Description: Simple wrapper for executing commands.
**************************************************/

#include "command.hpp"

#include <array>
#include <cstdio>
#include <cstring>
#include <memory>
#include <sstream>
#include <stdexcept>
#ifdef _WIN32
#include <windows.h>
#define SETENV(name, value) SetEnvironmentVariableA(name, value)
#define UNSETENV(name) SetEnvironmentVariableA(name, NULL)
#else
#include <cstdio>
#include <cstring>
#include <sys/wait.h>
#include <unistd.h>
#define SETENV(name, value) setenv(name, value, 1)
#define UNSETENV(name) unsetenv(name)
#endif

namespace Atom::System
{
std::string executeCommand(const std::string &command)
{
if (command.empty())
{
return "";
}
auto pipeDeleter = [](FILE *pipe)
{ if (pipe) pclose(pipe); };
std::unique_ptr<FILE, decltype(pipeDeleter)> pipe(popen(command.c_str(), "r"), pipeDeleter);

if (!pipe)
{
throw std::runtime_error("Error: failed to run command '" + command + "'.");
}

std::array<char, 4096> buffer{};
std::ostringstream output;

while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
output << buffer.data();
}

return output.str();
}

std::string executeCommandWithEnv(const std::string &command, const std::map<std::string, std::string> &envVars)
{
if (command.empty())
{
return "";
}
// 保存当前环境变量的状态
std::map<std::string, std::string> oldEnvVars;
for (const auto &var : envVars)
{
char *oldValue = std::getenv(var.first.c_str());
if (oldValue)
{
oldEnvVars[var.first] = oldValue;
}
#if defined(_WIN32) || defined(_WIN64)
SETENV(var.first.c_str(), var.second.c_str());
#else
SETENV(var.first.c_str(), var.second.c_str());
#endif
}

// 执行命令
auto result = executeCommand(command);

// 清理:恢复环境变量到之前的状态
for (const auto &var : envVars)
{
if (oldEnvVars.find(var.first) != oldEnvVars.end())
{
// 恢复旧值
SETENV(var.first.c_str(), oldEnvVars[var.first].c_str());
}
else
{
// 如果之前不存在,则删除
UNSETENV(var.first.c_str());
}
}

return result;
}

std::pair<std::string, int> executeCommandWithStatus(const std::string &command)
{
if (command.empty())
{
return {"", -1};
}
std::array<char, 4096> buffer{};
std::ostringstream output;

#ifdef _WIN32
// Windows implementation using _popen and _pclose
std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(command.c_str(), "r"), _pclose);
#else
// Linux implementation using popen and pclose
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
#endif

if (!pipe)
{
throw std::runtime_error("Error: failed to run command '" + command + "'.");
}

while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
output << buffer.data();
}

int status = -1;
#ifdef _WIN32
// Windows exit code retrieval
if (pipe)
{
status = 0;
}
#else
// Linux exit code retrieval
if (pipe)
{
status = WEXITSTATUS(pclose(pipe.get()));
}
#endif

return {output.str(), status};
}
}
Loading

0 comments on commit 344f931

Please sign in to comment.