21#include <dhtnet/multiplexed_socket.h>
22#include <dhtnet/connectionmanager.h>
24using namespace std::string_view_literals;
41 giterr_set_str(GITERR_NET,
"empty command");
45 auto delim = url.find(
'/');
46 if (delim == std::string::npos) {
47 giterr_set_str(GITERR_NET,
"malformed URL");
51 auto deviceId = url.substr(0, delim);
52 auto conversationId = url.substr(delim, url.size());
54 constexpr auto nullSeparator =
"\0"sv;
58 + conversationId.size()
61 + nullSeparator.size() ;
66 fmt::format_to_n(str.begin(), 4,
"{:04x}", total);
69 .append(conversationId)
70 .append(nullSeparator)
73 .append(nullSeparator);
75 git_buf_set(request, str.data(), str.size());
85 git_buf_dispose(&request);
90 auto sock = s->
socket.lock();
92 git_buf_dispose(&request);
95 if ((res = sock->write(
reinterpret_cast<const unsigned char*
>(request.ptr), request.size, ec))) {
97 git_buf_dispose(&request);
102 git_buf_dispose(&request);
107P2PStreamRead(git_smart_subtransport_stream* stream,
char* buffer,
size_t buflen,
size_t* read)
110 auto* fs =
reinterpret_cast<P2PStream*
>(stream);
111 auto sock = fs->
socket.lock();
113 giterr_set_str(GITERR_NET,
"unavailable socket");
120 if (!fs->sent_command && (res =
sendCmd(fs)) < 0)
125 size_t datalen = sock->waitForData(std::chrono::milliseconds(3600 * 1000 * 24), ec);
127 *read = sock->read(
reinterpret_cast<unsigned char*
>(buffer), std::min(datalen, buflen), ec);
133P2PStreamWrite(git_smart_subtransport_stream* stream,
const char* buffer,
size_t len)
135 auto* fs =
reinterpret_cast<P2PStream*
>(stream);
136 auto sock = fs->
socket.lock();
138 giterr_set_str(GITERR_NET,
"unavailable socket");
142 sock->write(
reinterpret_cast<const unsigned char*
>(buffer), len, ec);
144 giterr_set_str(GITERR_NET, ec.message().c_str());
156 git_smart_subtransport* transport,
158 git_smart_service_t action)
161 if (!sub || !sub->remote) {
166 auto repo = git_remote_owner(sub->remote);
168 JAMI_ERROR(
"No repository linked to the transport");
172 const auto* workdir = git_repository_workdir(repo);
174 JAMI_ERROR(
"No working linked to the repository");
177 std::string_view path = workdir;
178 auto delimConv = path.rfind(
"/conversations");
179 if (delimConv == std::string::npos) {
183 auto delimAccount = path.rfind(
'/', delimConv - 1);
184 if (delimAccount == std::string::npos && delimConv - 1 - delimAccount == 16) {
188 auto accountId = path.substr(delimAccount + 1, delimConv - 1 - delimAccount);
189 std::string_view gitUrl = url + (
"git://"sv).size();
190 auto delim = gitUrl.find(
'/');
191 if (delim == std::string::npos) {
195 auto deviceId = gitUrl.substr(0, delim);
196 auto conversationId = gitUrl.substr(delim + 1, gitUrl.size());
198 if (action == GIT_SERVICE_UPLOADPACK_LS) {
201 JAMI_ERROR(
"Unable to find related socket for {:s}, {:s}, {:s}",
207 auto stream = std::make_unique<P2PStream>();
208 stream->socket = gitSocket;
213 stream->url = gitUrl;
214 sub->stream = std::move(stream);
215 *out = &sub->stream->base;
217 }
else if (action == GIT_SERVICE_UPLOADPACK) {
219 *out = &sub->stream->base;
242 auto sub = std::make_unique<P2PSubTransport>();
243 sub->remote =
reinterpret_cast<git_remote*
>(payload);
244 auto* base = &sub->base;
268 git_smart_subtransport_definition def
271 reinterpret_cast<void*
>(owner)};
272 return git_transport_smart(out, owner, &def);
void insertGitTransport(git_smart_subtransport *tr, std::unique_ptr< P2PSubTransport > &&sub)
static LIBJAMI_TEST_EXPORT Manager & instance()
void eraseGitTransport(git_smart_subtransport *tr)
std::shared_ptr< dhtnet::ChannelSocket > gitSocket(std::string_view accountId, std::string_view deviceId, std::string_view conversationId)
Return current git socket used for a conversation.
int P2PStreamRead(git_smart_subtransport_stream *stream, char *buffer, size_t buflen, size_t *read)
Read on a channel socket.
int P2PStreamWrite(git_smart_subtransport_stream *stream, const char *buffer, size_t len)
int P2PSubTransportNew(P2PSubTransport **out, git_transport *, void *payload)
Create a new subtransport.
int P2PSubTransportClose(git_smart_subtransport *)
Close a subtransport Because we use a channel socket, we need to do nothing here.
void P2PStreamFree(git_smart_subtransport_stream *)
Free resources used by the stream.
int P2PSubTransportAction(git_smart_subtransport_stream **out, git_smart_subtransport *transport, const char *url, git_smart_service_t action)
Handles git actions.
int p2p_subtransport_cb(git_smart_subtransport **out, git_transport *owner, void *payload)
Setup the subtransport callback.
int sendCmd(P2PStream *s)
Send a git command on the linked socket.
int p2p_transport_cb(git_transport **out, git_remote *owner, void *)
Setup the transport callback.
int generateRequest(git_buf *request, const std::string &cmd, std::string_view url)
void P2PSubTransportFree(git_smart_subtransport *transport)
Free resources used by a transport.
constexpr auto UPLOAD_PACK_CMD
#define JAMI_ERROR(formatstr,...)
std::weak_ptr< dhtnet::ChannelSocket > socket
git_smart_subtransport base