Crow를 활용한 서버 구축

star-planet·2024년 9월 10일
0
post-thumbnail

국비과정을 진행하며 물류창고 출고 자동화시스템이라는 주제로 프로젝트를 진행하게 되었다.
통신을 위한 서버가 필요했고, 필자는 Crow를 사용해 보기로 하였다.

서버를 구축하면서 Crow, MySQL, ROS2를 사용했다.

기본 구조

Crow의 기본 구조는 다음과 같다.

#include "crow.h"

int main()
{
    crow::SimpleApp app;

    CROW_ROUTE(app, "/")([](){
        return "Hello world";
    });
    
    app.port(18080).multithreaded().run();
}

하나씩 확인해보자면

#include <crow.h>

Crow를 사용하기 위해서 추가하는 헤더파일이다.


crow::SimpleApp app;

App을 선언한다.


CROW_ROUTE(app, "/")([](){
        return "Hello world";
    });

경로(엔드포인트)를 추가한다.


app.port(18080).multithreaded().run();

App을 실행한다. (port()multithreaded()는 필수가 아니다)

Blueprint

Crow는 Flask-style blueprint를 지원한다.

/* 예시 */
CROW_BP_ROUTE(bp, "/route_name").methods(crow::HTTPMethod::POST)([this](const crow::request& req)
{
	// 구현할 기능
}

예시

구현한 서버 코드 중 일부를 발췌한 것이다.

// destination.hpp
#pragma once

#include <crow.h>
#include <memory.h>
#include <string>
#include <cppconn/driver.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>

#include "rclcpp/rclcpp.hpp"
#include "database_connection.hpp"
#include "outbound_delivery_robot_interfaces/msg/location.hpp"

class Destination : public DatabaseConnection, rclcpp::Node
{
    public:
        Destination(const std::string& configFile): DatabaseConnection(configFile), Node("send_destination"), bp("destination")
        {
            publisher_ = this->create_publisher<outbound_delivery_robot_interfaces::msg::Location>("location", 10);

            CROW_BP_ROUTE(bp, "/send").methods(crow::HTTPMethod::POST)([this](const crow::request& req)
            {
                auto data = crow::json::load(req.body);
                if (!data) {return crow::response(400, "Invalid JSON"); }

                auto robot_id = data["robot_id"].s();
                auto product = data["task"].s();

                auto conn = Connection();

                std::unique_ptr<sql::PreparedStatement> pstmt(conn->prepareStatement("SELECT * FROM location WHERE product=?"));
                pstmt->setString(1, std::string(product));

                std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
                if (res->next())
                {
                    location_msg.robot_id = std::stoi(robot_id);
                    location_msg.section = res->getString("section");
                    location_msg.x = res->getDouble("x");
                    location_msg.y = res->getDouble("y");
                    location_msg.z = res->getDouble("z");
                    location_msg.w = res->getDouble("w");

                    publisher_->publish(location_msg);
                }

                return crow::response(200, "Location published successfully\n");
            });
        }

        crow::Blueprint& getBlueprint()
        {
            return bp;
        }

    private:
        crow::Blueprint bp;
        rclcpp::Publisher<outbound_delivery_robot_interfaces::msg::Location>::SharedPtr publisher_;
        outbound_delivery_robot_interfaces::msg::Location location_msg;
};
// main.cpp
#include "rclcpp/rclcpp.hpp"

#include <crow.h>
#include <filesystem>
#include <ament_index_cpp/get_package_share_directory.hpp>

#include "server/destination.hpp"

int main(int argc, char* argv[])
{
    rclcpp::init(argc, argv);

    std::string package_share_directory = ament_index_cpp::get_package_share_directory("server");
    std::string configFile = (std::filesystem::path(package_share_directory) / "config" / "database.yaml").string();
    
    Destination destination(configFile);

    crow::SimpleApp app;
    app.loglevel(crow::LogLevel::Info);

    app.register_blueprint(destination.getBlueprint());

    app.port(5000).multithreaded().run();

    rclcpp::shutdown();

    return 0;
}

0개의 댓글

관련 채용 정보