21#include <dhtnet/multiplexed_socket.h>
22#include <dhtnet/connectionmanager.h>
24using namespace std::string_view_literals;
29generateRequest(git_buf* request,
const std::string& cmd,
const std::string_view& url)
32 giterr_set_str(GITERR_NET,
"empty command");
36 auto delim = url.find(
'/');
37 if (delim == std::string::npos) {
38 giterr_set_str(GITERR_NET,
"malformed URL");
42 auto deviceId = url.substr(0, delim);
43 auto conversationId = url.substr(delim, url.size());
45 auto nullSeparator =
"\0"sv;
49 + conversationId.size()
52 + nullSeparator.size() ;
54 std::ostringstream streamed;
55 streamed << std::setw(4) << std::setfill(
'0') << std::hex << (total & 0x0FFFF) << cmd;
56 streamed <<
" " << conversationId;
57 streamed << nullSeparator <<
HOST_TAG << deviceId << nullSeparator;
58 auto str = streamed.str();
59 git_buf_set(request, str.c_str(), str.size());
69 git_buf_dispose(&request);
74 auto sock = s->
socket.lock();
76 git_buf_dispose(&request);
79 if ((res = sock->write(
reinterpret_cast<const unsigned char*
>(request.ptr), request.size, ec))) {
81 git_buf_dispose(&request);
86 git_buf_dispose(&request);
91P2PStreamRead(git_smart_subtransport_stream* stream,
char* buffer,
size_t buflen,
size_t* read)
94 auto* fs =
reinterpret_cast<P2PStream*
>(stream);
95 auto sock = fs->
socket.lock();
97 giterr_set_str(GITERR_NET,
"unavailable socket");
104 if (!fs->sent_command && (res =
sendCmd(fs)) < 0)
109 size_t datalen = sock->waitForData(std::chrono::milliseconds(3600 * 1000 * 24), ec);
111 *read = sock->read(
reinterpret_cast<unsigned char*
>(buffer), std::min(datalen, buflen), ec);
117P2PStreamWrite(git_smart_subtransport_stream* stream,
const char* buffer,
size_t len)
119 auto* fs =
reinterpret_cast<P2PStream*
>(stream);
120 auto sock = fs->
socket.lock();
122 giterr_set_str(GITERR_NET,
"unavailable socket");
126 sock->write(
reinterpret_cast<const unsigned char*
>(buffer), len, ec);
128 giterr_set_str(GITERR_NET, ec.message().c_str());
140 git_smart_subtransport* transport,
142 git_smart_service_t action)
145 if (!sub || !sub->remote) {
150 auto repo = git_remote_owner(sub->remote);
152 JAMI_ERROR(
"No repository linked to the transport");
156 const auto* workdir = git_repository_workdir(repo);
158 JAMI_ERROR(
"No working linked to the repository");
161 std::string_view path = workdir;
162 auto delimConv = path.rfind(
"/conversations");
163 if (delimConv == std::string::npos) {
167 auto delimAccount = path.rfind(
'/', delimConv - 1);
168 if (delimAccount == std::string::npos && delimConv - 1 - delimAccount == 16) {
172 auto accountId = path.substr(delimAccount + 1, delimConv - 1 - delimAccount);
173 std::string_view gitUrl = url + (
"git://"sv).size();
174 auto delim = gitUrl.find(
'/');
175 if (delim == std::string::npos) {
179 auto deviceId = gitUrl.substr(0, delim);
180 auto conversationId = gitUrl.substr(delim + 1, gitUrl.size());
182 if (action == GIT_SERVICE_UPLOADPACK_LS) {
185 JAMI_ERROR(
"Unable to find related socket for {:s}, {:s}, {:s}",
191 auto stream = std::make_unique<P2PStream>();
192 stream->socket = gitSocket;
197 stream->url = gitUrl;
198 sub->stream = std::move(stream);
199 *out = &sub->stream->base;
201 }
else if (action == GIT_SERVICE_UPLOADPACK) {
203 *out = &sub->stream->base;
226 auto sub = std::make_unique<P2PSubTransport>();
227 sub->remote =
reinterpret_cast<git_remote*
>(payload);
228 auto* base = &sub->base;
252 git_smart_subtransport_definition def
255 reinterpret_cast<void*
>(owner)};
256 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.
int generateRequest(git_buf *request, const std::string &cmd, const std::string_view &url)
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.
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