From 1727bf620dfb85d17b5664c88a70a23e5a7c4ffd Mon Sep 17 00:00:00 2001
From: Konstantina Skovola <konstantina.skovola@cern.ch>
Date: Mon, 24 Mar 2025 16:36:30 +0100
Subject: [PATCH] Add admin ls impl

---
 .../CtaAdminClientReadReactor.hpp             |  9 ++
 frontend/grpc/callback_api/CtaAdminServer.hpp |  3 +
 frontend/grpc/callback_api/ServerAdminLs.hpp  | 93 +++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 frontend/grpc/callback_api/ServerAdminLs.hpp

diff --git a/frontend/grpc/callback_api/CtaAdminClientReadReactor.hpp b/frontend/grpc/callback_api/CtaAdminClientReadReactor.hpp
index bc87f6eb45..53622cf0ee 100644
--- a/frontend/grpc/callback_api/CtaAdminClientReadReactor.hpp
+++ b/frontend/grpc/callback_api/CtaAdminClientReadReactor.hpp
@@ -78,6 +78,9 @@ public:
                             case cta::admin::HeaderType::DRIVE_LS:
                                 m_textFormatter.printDriveLsHeader();
                                 break;
+                            case cta::admin::HeaderType::ADMIN_LS:
+                                m_textFormatter.printAdminLsHeader();
+                                break;
                             default:
                                 // keep compiler happy
                                 break;
@@ -135,6 +138,12 @@ public:
                         m_textFormatter.print(driveLsItem);
                         break;
                     }
+                    case cta::xrd::Data::kAdlsItem:
+                    {
+                        const cta::admin::AdminLsItem& adminLsItem = m_response.data().adls_item();
+                        m_textFormatter.print(adminLsItem);
+                        break;
+                    }
                     default:
                         // keep compiler happy
                         break;
diff --git a/frontend/grpc/callback_api/CtaAdminServer.hpp b/frontend/grpc/callback_api/CtaAdminServer.hpp
index e93a137f99..0ac1b9a8e5 100644
--- a/frontend/grpc/callback_api/CtaAdminServer.hpp
+++ b/frontend/grpc/callback_api/CtaAdminServer.hpp
@@ -27,6 +27,7 @@
 #include "ServerVirtualOrganizationLs.hpp"
 #include "ServerDiskInstanceLs.hpp"
 #include "ServerDriveLs.hpp"
+#include "ServerAdminLs.hpp"
 
 #include <grpcpp/grpcpp.h>
 
@@ -110,6 +111,8 @@ CtaRpcStreamImpl::GenericAdminStream(::grpc::CallbackServerContext* context, con
       return new DiskInstanceLsWriteReactor(m_catalogue, m_scheduler, request);
     case cmd_pair(cta::admin::AdminCmd::CMD_DRIVE, cta::admin::AdminCmd::SUBCMD_LS):
       return new DriveLsWriteReactor(m_catalogue, m_scheduler, m_lc, request);
+    case cmd_pair(cta::admin::AdminCmd::CMD_ADMIN, cta::admin::AdminCmd::SUBCMD_LS):
+      return new AdminLsWriteReactor(m_catalogue, m_scheduler, request);
     default:
       // make the compiler happy maybe and return
       return new TapeLsWriteReactor(m_catalogue, m_scheduler, request);
diff --git a/frontend/grpc/callback_api/ServerAdminLs.hpp b/frontend/grpc/callback_api/ServerAdminLs.hpp
new file mode 100644
index 0000000000..bbad3e7123
--- /dev/null
+++ b/frontend/grpc/callback_api/ServerAdminLs.hpp
@@ -0,0 +1,93 @@
+// #include "CtaAdminServer.hpp" // need this for the class CtaAdminServerWriteReactor, nothing else
+#include <catalogue/Catalogue.hpp>
+#include <scheduler/Scheduler.hpp>
+
+#include "cta_frontend.pb.h"
+#include "cta_frontend.grpc.pb.h"
+
+#include <grpcpp/grpcpp.h>
+#include "common/dataStructures/LabelFormatSerDeser.hpp"
+#include "common/dataStructures/AdminUser.hpp"
+
+namespace cta::frontend::grpc {
+
+class AdminLsWriteReactor : public ::grpc::ServerWriteReactor<cta::xrd::StreamResponse> /* CtaAdminServerWriteReactor */ {
+    public:
+        AdminLsWriteReactor(cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler, const cta::xrd::Request* request);
+        void OnWriteDone(bool ok) override {
+            std::cout << "In AdminLsWriteReactor, we are inside OnWriteDone" << std::endl;
+            if (!ok) {
+                std::cout << "Unexpected failure in OnWriteDone" << std::endl;
+                Finish(Status(::grpc::StatusCode::UNKNOWN, "Unexpected Failure in OnWriteDone"));
+            }
+            std::cout << "Calling NextWrite inside server's OnWriteDone" << std::endl;
+            NextWrite();
+        }
+        void OnDone() override;
+        void NextWrite();
+    private:
+        std::list<cta::common::dataStructures::AdminUser> m_adminList; 
+        bool m_isHeaderSent; // or could be a static variable in the function NextWrite()
+        cta::xrd::StreamResponse m_response;
+        std::list<cta::common::dataStructures::AdminUser>::const_iterator next_admin;
+};
+
+void AdminLsWriteReactor::OnDone() {
+    std::cout << "In AdminLsWriteReactor::OnDone(), about to delete this object" << std::endl;
+    delete this;
+}
+
+AdminLsWriteReactor::AdminLsWriteReactor(cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler, const cta::xrd::Request* request)
+    : m_adminList(catalogue.AdminUser()->getAdminUsers()),
+      m_isHeaderSent(false) {
+    using namespace cta::admin;
+
+    std::cout << "In AdminLsWriteReactor constructor, just entered!" << std::endl;
+
+    next_admin = m_adminList.cbegin();
+    NextWrite();
+}
+
+void AdminLsWriteReactor::NextWrite() {
+    std::cout << "In AdminLsWriteReactor::NextWrite(), just entered!" << std::endl;
+    m_response.Clear();
+    // is this the first item? Then write the header
+    if (!m_isHeaderSent) {
+        cta::xrd::Response *header = new cta::xrd::Response();
+        std::cout << "header is not sent, sending the header" << std::endl;
+        header->set_type(cta::xrd::Response::RSP_SUCCESS);
+        header->set_show_header(cta::admin::HeaderType::ADMIN_LS);
+        m_response.set_allocated_header(header); // now the message takes ownership of the allocated object, we don't need to free header
+
+        m_isHeaderSent = true;
+        std::cout << "about to call StartWrite on the server side" << std::endl;
+        StartWrite(&m_response); // this will trigger the OnWriteDone method
+        std::cout << "called StartWrite on the server" << std::endl;
+        return; // because we'll be called in a loop by OnWriteDone
+    } else {
+        while(next_admin != m_adminList.cend()) {
+            const auto& ad = *next_admin;
+            next_admin++;
+            cta::xrd::Data* data = new cta::xrd::Data();
+            cta::admin::AdminLsItem *ad_item = data->mutable_adls_item();
+            
+            ad_item->set_user(ad.name);
+            ad_item->mutable_creation_log()->set_username(ad.creationLog.username);
+            ad_item->mutable_creation_log()->set_host(ad.creationLog.host);
+            ad_item->mutable_creation_log()->set_time(ad.creationLog.time);
+            ad_item->mutable_last_modification_log()->set_username(ad.lastModificationLog.username);
+            ad_item->mutable_last_modification_log()->set_host(ad.lastModificationLog.host);
+            ad_item->mutable_last_modification_log()->set_time(ad.lastModificationLog.time);
+            ad_item->set_comment(ad.comment);
+
+            std::cout << "Calling StartWrite on the server, with some data this time" << std::endl;
+            m_response.set_allocated_data(data);
+            StartWrite(&m_response);
+            return; // because we will be called in a loop by OnWriteDone()
+        } // end while
+        std::cout << "Finishing the call on the server side" << std::endl;
+        // Finish the call
+        Finish(::grpc::Status::OK);
+    }
+}
+} // namespace cta::frontend::grpc
\ No newline at end of file
-- 
GitLab