반응형


#pragma once
#include <sdbus-c++/sdbus-c++.h>
#include <unordered_map>
#include <string>
#include <functional>
#include <iostream>

class ServiceWatcher
{
public:
    using AppearedCallback    = std::function<void(const std::string& name,
                                                   const std::string& newOwner)>;
    using DisappearedCallback = std::function<void(const std::string& name,
                                                   const std::string& oldOwner)>;

    explicit ServiceWatcher(sdbus::IConnection& conn)
        : conn_(conn)
    {}

    // ✅ sender 감시 추가
    void watch(const std::string&    sender,
               AppearedCallback      onAppeared,
               DisappearedCallback   onDisappeared)
    {
        // 이미 감시 중이면 무시
        if (slots_.count(sender)) {
            std::cout << "[Watcher] Already watching: " << sender << "\n";
            return;
        }

        const std::string matchRule =
            "type='signal',"
            "sender='org.freedesktop.DBus',"
            "interface='org.freedesktop.DBus',"
            "member='NameOwnerChanged',"
            "arg0='" + sender + "'";

        // ✅ return_slot으로 slot 반환받아 map에 보관
        auto slot = conn_.addMatch(
            matchRule,
            [sender, onAppeared, onDisappeared](sdbus::Message msg) {
                std::string name, oldOwner, newOwner;
                msg >> name >> oldOwner >> newOwner;

                if (oldOwner.empty() && !newOwner.empty()) {
                    if (onAppeared)
                        onAppeared(name, newOwner);
                } else if (!oldOwner.empty() && newOwner.empty()) {
                    if (onDisappeared)
                        onDisappeared(name, oldOwner);
                }
            },
            sdbus::return_slot  // ✅ slot 반환 받기
        );

        slots_.emplace(sender, std::move(slot));
        std::cout << "[Watcher] Started watching: " << sender << "\n";
    }

    // ✅ sender 감시 해제
    void unwatch(const std::string& sender)
    {
        auto it = slots_.find(sender);
        if (it == slots_.end()) {
            std::cout << "[Watcher] Not watching: " << sender << "\n";
            return;
        }

        // slot 소멸 → match rule 자동 해제
        slots_.erase(it);
        std::cout << "[Watcher] Stopped watching: " << sender << "\n";
    }

    // ✅ 현재 감시 중인 sender 목록
    std::vector<std::string> watchList() const
    {
        std::vector<std::string> list;
        for (const auto& [sender, _] : slots_) {
            list.push_back(sender);
        }
        return list;
    }

    // ✅ 모든 감시 해제
    void unwatchAll()
    {
        slots_.clear();
        std::cout << "[Watcher] All watches cleared\n";
    }

private:
    sdbus::IConnection& conn_;

    // sender → slot (slot 소멸 시 match rule 자동 해제)
    std::unordered_map<std::string, sdbus::Slot> slots_;
};





#include <sdbus-c++/sdbus-c++.h>
#include <iostream>

class ServiceWatcher
{
public:
    ServiceWatcher(sdbus::IConnection& conn,
                   std::string watchedService)
        : conn_(conn)
        , watchedService_(std::move(watchedService))
    {
        // NameOwnerChanged 시그널 match rule 등록
        const std::string matchRule =
            "type='signal',"
            "sender='org.freedesktop.DBus',"
            "interface='org.freedesktop.DBus',"
            "member='NameOwnerChanged',"
            "arg0='" + watchedService_ + "'";

        // ✅ v2.0.0: addMatch (floating - connection 수명에 묶임)
        conn_.addMatch(
            matchRule,
            [this](sdbus::Message msg) {
                onNameOwnerChanged(msg);
            }
        );

        std::cout << "[Watcher] Watching: " << watchedService_ << "\n";
    }

private:
    void onNameOwnerChanged(sdbus::Message& msg)
    {
        std::string name, oldOwner, newOwner;
        msg >> name >> oldOwner >> newOwner;

        if (oldOwner.empty() && !newOwner.empty()) {
            // ✅ 서비스 등장
            onServiceAppeared(name, newOwner);
        } else if (!oldOwner.empty() && newOwner.empty()) {
            // ✅ 서비스 사라짐
            onServiceDisappeared(name, oldOwner);
        }
    }

    void onServiceAppeared(const std::string& name,
                           const std::string& newOwner)
    {
        std::cout << "[Watcher] Appeared : " << name
                  << " (owner: " << newOwner << ")\n";
        // 여기서 원하는 작업 수행
    }

    void onServiceDisappeared(const std::string& name,
                              const std::string& oldOwner)
    {
        std::cout << "[Watcher] Disappeared: " << name
                  << " (was: " << oldOwner << ")\n";
        // 여기서 원하는 작업 수행
    }

    sdbus::IConnection& conn_;
    std::string         watchedService_;
};

int main()
{
    auto conn = sdbus::createSessionBusConnection();

    // ✅ org.example.Calculator 서비스를 감시
    ServiceWatcher watcher{*conn, "org.example.Calculator"};

    std::cout << "Watching for service...\n";
    conn->enterEventLoop();

    return 0;
}

반응형