fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
ServiceManager.cpp
1/*
2 * MIT License
3 *
4 * Copyright (c) 2026 Adriano dos Santos Fernandes
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "ServiceManager.h"
26#include "Client.h"
27#include "Exception.h"
28#include <cassert>
29
30using namespace fbcpp;
31using namespace fbcpp::impl;
32
33
34static void emitVerboseChunk(
35 std::string& pendingLine, const std::string_view chunk, const ServiceManager::VerboseOutput& verboseOutput)
36{
37 if (!verboseOutput || chunk.empty())
38 return;
39
40 for (char ch : chunk)
41 {
42 if (ch == '\r')
43 continue;
44
45 if (ch == '\n')
46 {
47 verboseOutput(pendingLine);
48 pendingLine.clear();
49 }
50 else
51 pendingLine += ch;
52 }
53}
54
55
57 : client{&client}
58{
59 const auto master = client.getMaster();
60 StatusWrapper statusWrapper{client};
61
62 auto spbBuilder = fbUnique(client.getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::SPB_ATTACH,
63 reinterpret_cast<const std::uint8_t*>(options.getSpb().data()),
64 static_cast<unsigned>(options.getSpb().size())));
65
66 if (const auto userName = options.getUserName())
67 spbBuilder->insertString(&statusWrapper, isc_spb_user_name, userName->c_str());
68
69 if (const auto password = options.getPassword())
70 spbBuilder->insertString(&statusWrapper, isc_spb_password, password->c_str());
71
72 if (const auto role = options.getRole())
73 spbBuilder->insertString(&statusWrapper, isc_spb_sql_role_name, role->c_str());
74
75 auto dispatcher = fbRef(master->getDispatcher());
76 const auto spbBuffer = spbBuilder->getBuffer(&statusWrapper);
77 const auto spbBufferLen = spbBuilder->getBufferLength(&statusWrapper);
78 auto service = options.getServiceManagerName();
79
80 if (const auto host = options.getServer())
81 service = host.value() + ':' + service;
82
83 handle.reset(dispatcher->attachServiceManager(&statusWrapper, service.c_str(), spbBufferLen, spbBuffer));
84}
85
87{
88 detachHandle();
89}
90
91void ServiceManager::startAction(const std::vector<std::uint8_t>& spb)
92{
93 assert(isValid());
94
95 StatusWrapper statusWrapper{*client};
96 handle->start(&statusWrapper, static_cast<unsigned>(spb.size()), spb.data());
97}
98
99void ServiceManager::waitForCompletion(const VerboseOutput& verboseOutput, bool requestStdin)
100{
101 assert(isValid());
102
103 StatusWrapper statusWrapper{*client};
104 auto receiveBuilder =
105 fbUnique(client->getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::SPB_RECEIVE, nullptr, 0));
106 receiveBuilder->insertTag(&statusWrapper, verboseOutput ? isc_info_svc_line : isc_info_svc_to_eof);
107
108 if (requestStdin)
109 receiveBuilder->insertTag(&statusWrapper, isc_info_svc_stdin);
110
111 const auto receiveLength = receiveBuilder->getBufferLength(&statusWrapper);
112 const auto* receiveBuffer = receiveBuilder->getBuffer(&statusWrapper);
113
114 std::vector<std::uint8_t> buffer(16u * 1024u);
115 std::string pendingLine;
116 unsigned stdinRequest = 0;
117
118 for (bool running = true; running;)
119 {
120 auto sendBuilder =
121 fbUnique(client->getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::SPB_SEND, nullptr, 0));
122
123 if (stdinRequest)
124 throw FbCppException("Service requested stdin input");
125
126 std::fill(buffer.begin(), buffer.end(), 0);
127 handle->query(&statusWrapper, sendBuilder->getBufferLength(&statusWrapper),
128 sendBuilder->getBuffer(&statusWrapper), receiveLength, receiveBuffer, static_cast<unsigned>(buffer.size()),
129 buffer.data());
130
131 auto responseBuilder = fbUnique(client->getUtil()->getXpbBuilder(
132 &statusWrapper, fb::IXpbBuilder::SPB_RESPONSE, buffer.data(), static_cast<unsigned>(buffer.size())));
133
134 stdinRequest = 0;
135 int outputLength = 0;
136 bool notReady = false;
137
138 for (responseBuilder->rewind(&statusWrapper); running && !responseBuilder->isEof(&statusWrapper);
139 responseBuilder->moveNext(&statusWrapper))
140 {
141 switch (responseBuilder->getTag(&statusWrapper))
142 {
143 case isc_info_svc_line:
144 {
145 const auto* line = responseBuilder->getString(&statusWrapper);
146 const auto length = static_cast<int>(responseBuilder->getLength(&statusWrapper));
147 if (verboseOutput && length > 0)
148 verboseOutput(std::string_view{line, static_cast<size_t>(length)});
149 outputLength = length;
150 break;
151 }
152
153 case isc_info_svc_to_eof:
154 {
155 const auto* bytes = reinterpret_cast<const char*>(responseBuilder->getBytes(&statusWrapper));
156 const auto length = static_cast<int>(responseBuilder->getLength(&statusWrapper));
157 emitVerboseChunk(pendingLine, std::string_view{bytes, static_cast<size_t>(length)}, verboseOutput);
158 outputLength = length;
159 break;
160 }
161
162 case isc_info_svc_stdin:
163 stdinRequest = static_cast<unsigned>(responseBuilder->getInt(&statusWrapper));
164 break;
165
166 case isc_info_end:
167 running = false;
168 break;
169
170 case isc_info_truncated:
171 case isc_info_data_not_ready:
172 case isc_info_svc_timeout:
173 notReady = true;
174 break;
175
176 default:
177 break;
178 }
179 }
180
181 if (outputLength || stdinRequest || notReady)
182 running = true;
183 }
184
185 if (verboseOutput && !pendingLine.empty())
186 verboseOutput(pendingLine);
188
189void ServiceManager::detachHandle()
190{
191 assert(isValid());
192
193 StatusWrapper statusWrapper{*client};
194 handle->detach(&statusWrapper);
195 handle.reset();
196}
Represents a Firebird client library instance.
Definition Client.h:53
fb::IUtil * getUtil()
Returns a Firebird IUtil interface.
Definition Client.h:144
fb::IMaster * getMaster() noexcept
Returns the Firebird IMaster interface.
Definition Client.h:136
Base exception class for all fb-cpp exceptions.
Definition Exception.h:230
Represents options used when creating a ServiceManager object.
const std::vector< std::uint8_t > & getSpb() const
Returns the raw service attach SPB.
const std::optional< std::string > & getServer() const
Returns the server used to attach to the service manager.
const std::string & getServiceManagerName() const
Returns the service manager name.
const std::optional< std::string > & getPassword() const
Returns the password used to attach to the service manager.
const std::optional< std::string > & getUserName() const
Returns the user name used to attach to the service manager.
const std::optional< std::string > & getRole() const
Returns the role used to attach to the service manager.
ServiceManager(Client &client, const ServiceManagerOptions &options={})
Attaches to the service manager specified by the given options.
void disconnect()
Detaches from the service manager.
bool isValid() noexcept
Returns whether the ServiceManager object is valid.
std::function< void(std::string_view line)> VerboseOutput
Function invoked when a verbose service output line is available.
fb-cpp namespace.
Definition Attachment.h:42
FbRef< T > fbRef(T *arg) noexcept
Creates a reference-counted smart pointer for a Firebird object.
Definition SmartPtrs.h:229
FbUniquePtr< T > fbUnique(T *obj) noexcept
Creates a unique pointer for a Firebird disposable object.
Definition SmartPtrs.h:59