Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions endpoint/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ if(PRIVMX_BUILD_ENDPOINT_ENDPOINT)
add_subdirectory(thread)
add_subdirectory(store)
add_subdirectory(kvdb)
add_subdirectory(lock)
add_subdirectory(inbox)
add_subdirectory(stream)
add_subdirectory(search)
Expand Down
24 changes: 24 additions & 0 deletions endpoint/lock/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(INCLUDE_PUB_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include_pub)

if(BUILD_SHARED_LIBS)
add_library(privmxendpointlock SHARED ${SOURCES})
else()
add_library(privmxendpointlock STATIC ${SOURCES})
endif()
target_include_directories(privmxendpointlock PUBLIC ${INCLUDE_DIRS} PUBLIC ${INCLUDE_PUB_DIRS})
target_compile_options(privmxendpointlock PRIVATE -Wall -Wextra -fPIC)
target_link_libraries(privmxendpointlock PRIVATE Poco::Foundation privmx privmxendpointcore)
if(BUILD_SHARED_LIBS)
set_target_properties(privmxendpointlock PROPERTIES POSITION_INDEPENDENT_CODE True)
endif()
install(TARGETS privmxendpointlock DESTINATION lib)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include_pub/privmx DESTINATION include)
if(PRIVMX_INSTALL_PRIVATE_HEADERS)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/privmx DESTINATION include)
endif()
if(PRIVMX_WERROR)
target_compile_options(privmxendpointlock PRIVATE -Werror)
endif()
set_target_properties(privmxendpointlock PROPERTIES COMPILE_DEFINITIONS "MINIMAL_BUILD")
47 changes: 47 additions & 0 deletions endpoint/lock/include/privmx/endpoint/lock/LockApiImpl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPIIMPL_HPP_
#define _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPIIMPL_HPP_

#include <string>

#include <privmx/privfs/gateway/RpcGateway.hpp>
#include <privmx/utils/ManualManagedClass.hpp>

#include "privmx/endpoint/lock/LockApi.hpp"
#include "privmx/endpoint/lock/ServerApi.hpp"
#include "privmx/endpoint/lock/Types.hpp"

namespace privmx {
namespace endpoint {
namespace lock {

class LockApiImpl : public privmx::utils::ManualManagedClass<LockApiImpl> {
public:
LockApiImpl(const privfs::RpcGateway::Ptr& gateway);

LockOperationResult lock(const std::string& resourceId, const std::string& uuid, LockLevel lockLevel);
LockOperationResult unlock(const std::string& resourceId, const std::string& uuid, LockLevel lockLevel);
bool checkReservedLock(const std::string& resourceId, const std::string& uuid);

private:
static std::string lockLevelToString(LockLevel level);
static LockLevel lockLevelFromString(const std::string& level);

ServerApi _serverApi;
};

} // namespace lock
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPIIMPL_HPP_
42 changes: 42 additions & 0 deletions endpoint/lock/include/privmx/endpoint/lock/ServerApi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_LOCK_SERVER_API_HPP_
#define _PRIVMXLIB_ENDPOINT_LOCK_SERVER_API_HPP_

#include <privmx/privfs/gateway/RpcGateway.hpp>

#include "privmx/endpoint/lock/ServerTypes.hpp"

namespace privmx {
namespace endpoint {
namespace lock {

class ServerApi {
public:
ServerApi(privmx::privfs::RpcGateway::Ptr gateway);

server::LockOperationResult lockLock(server::LockLockModel model);
server::LockOperationResult lockUnlock(server::LockUnlockModel model);
server::LockCheckReservedLockResult lockCheckReservedLock(server::LockCheckReservedLockModel model);

private:
template<typename T>
T request(const std::string& method, Poco::JSON::Object::Ptr params);

privfs::RpcGateway::Ptr _gateway;
};

} // namespace lock
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_LOCK_SERVER_API_HPP_
55 changes: 55 additions & 0 deletions endpoint/lock/include/privmx/endpoint/lock/ServerTypes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_LOCK_SERVERTYPES_HPP_
#define _PRIVMXLIB_ENDPOINT_LOCK_SERVERTYPES_HPP_

#include <string>

#include <privmx/utils/JsonHelper.hpp>

namespace privmx {
namespace endpoint {
namespace lock {
namespace server {

#define LOCK_LOCK_MODEL_FIELDS(F) \
F(resourceId, std::string) \
F(uuid, std::string) \
F(lockLevel, std::string)
JSON_STRUCT(LockLockModel, LOCK_LOCK_MODEL_FIELDS);

#define LOCK_UNLOCK_MODEL_FIELDS(F) \
F(resourceId, std::string) \
F(uuid, std::string) \
F(lockLevel, std::string)
JSON_STRUCT(LockUnlockModel, LOCK_UNLOCK_MODEL_FIELDS);

// success: bool, currentLevel: string ("none"|"shared"|"reserved"|"pending"|"exclusive")
#define LOCK_OPERATION_RESULT_FIELDS(F) \
F(success, bool) \
F(currentLevel, std::string)
JSON_STRUCT(LockOperationResult, LOCK_OPERATION_RESULT_FIELDS);

#define LOCK_CHECK_RESERVED_LOCK_MODEL_FIELDS(F) \
F(resourceId, std::string) \
F(uuid, std::string)
JSON_STRUCT(LockCheckReservedLockModel, LOCK_CHECK_RESERVED_LOCK_MODEL_FIELDS);

#define LOCK_CHECK_RESERVED_LOCK_RESULT_FIELDS(F) F(reserved, bool)
JSON_STRUCT(LockCheckReservedLockResult, LOCK_CHECK_RESERVED_LOCK_RESULT_FIELDS);

} // namespace server
} // namespace lock
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_LOCK_SERVERTYPES_HPP_
32 changes: 32 additions & 0 deletions endpoint/lock/include/privmx/endpoint/lock/VarDeserializer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_LOCK_VARDESERIALIZER_HPP_
#define _PRIVMXLIB_ENDPOINT_LOCK_VARDESERIALIZER_HPP_

#include <Poco/Dynamic/Var.h>

#include <privmx/endpoint/core/VarDeserializer.hpp>

#include "privmx/endpoint/lock/Types.hpp"

namespace privmx {
namespace endpoint {
namespace core {

template<>
lock::LockLevel VarDeserializer::deserialize<lock::LockLevel>(const Poco::Dynamic::Var& val, const std::string& name);

} // namespace core
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_LOCK_VARDESERIALIZER_HPP_
32 changes: 32 additions & 0 deletions endpoint/lock/include/privmx/endpoint/lock/VarSerializer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_LOCK_VARSERIALIZER_HPP_
#define _PRIVMXLIB_ENDPOINT_LOCK_VARSERIALIZER_HPP_

#include <Poco/Dynamic/Var.h>

#include <privmx/endpoint/core/VarSerializer.hpp>

#include "privmx/endpoint/lock/Types.hpp"

namespace privmx {
namespace endpoint {
namespace core {

template<>
Poco::Dynamic::Var VarSerializer::serialize<lock::LockOperationResult>(const lock::LockOperationResult& val);

} // namespace core
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_LOCK_VARSERIALIZER_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPIVARINTERFACE_HPP_
#define _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPIVARINTERFACE_HPP_

#include <map>

#include <Poco/Dynamic/Var.h>

#include "privmx/endpoint/lock/LockApi.hpp"
#include "privmx/endpoint/lock/VarDeserializer.hpp"
#include "privmx/endpoint/lock/VarSerializer.hpp"

namespace privmx {
namespace endpoint {
namespace lock {

class LockApiVarInterface {
public:
enum METHOD {
Create = 0,
Lock = 1,
Unlock = 2,
CheckReservedLock = 3,
};

LockApiVarInterface(core::Connection connection, const core::VarSerializer& serializer)
: _connection(std::move(connection)), _serializer(serializer) {}

Poco::Dynamic::Var create(const Poco::Dynamic::Var& args);
Poco::Dynamic::Var lock(const Poco::Dynamic::Var& args);
Poco::Dynamic::Var unlock(const Poco::Dynamic::Var& args);
Poco::Dynamic::Var checkReservedLock(const Poco::Dynamic::Var& args);

Poco::Dynamic::Var exec(METHOD method, const Poco::Dynamic::Var& args);

LockApi getApi() const { return _lockApi; }

private:
static std::map<METHOD, Poco::Dynamic::Var (LockApiVarInterface::*)(const Poco::Dynamic::Var&)> methodMap;

core::Connection _connection;
LockApi _lockApi;
core::VarDeserializer _deserializer;
core::VarSerializer _serializer;
};

} // namespace lock
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPIVARINTERFACE_HPP_
87 changes: 87 additions & 0 deletions endpoint/lock/include_pub/privmx/endpoint/lock/LockApi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPI_HPP_
#define _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPI_HPP_

#include <string>

#include "privmx/endpoint/core/Connection.hpp"
#include "privmx/endpoint/lock/Types.hpp"
#include <privmx/endpoint/core/ExtendedPointer.hpp>

namespace privmx {
namespace endpoint {
namespace lock {

class LockApiImpl;

/**
* 'LockApi' provides distributed locking of arbitrary resources identified by a string ID.
* Lock levels follow the SQLite locking model: NONE < SHARED < RESERVED < PENDING < EXCLUSIVE.
*/
class LockApi : public privmx::endpoint::core::ExtendedPointer<LockApiImpl> {
public:
/**
* Creates an instance of 'LockApi'.
*
* @param connection instance of 'Connection'
* @return LockApi object
*/
static LockApi create(core::Connection& connection);

/**
* //doc-gen:ignore
*/
LockApi();
LockApi(const LockApi& obj);
LockApi& operator=(const LockApi& obj);
LockApi(LockApi&& obj);
~LockApi();

/**
* Attempts to acquire a lock on a resource at the requested level.
*
* @param resourceId identifier of the resource to lock
* @param uuid caller-unique identifier used to track lock ownership
* @param lockLevel desired lock level (SHARED, RESERVED, PENDING, or EXCLUSIVE)
* @return result indicating success and the current lock level held by the caller
*/
LockOperationResult lock(const std::string& resourceId, const std::string& uuid, LockLevel lockLevel);

/**
* Releases or downgrades a lock held on a resource.
*
* @param resourceId identifier of the resource to unlock
* @param uuid caller-unique identifier matching the one used during lock acquisition
* @param lockLevel target level to downgrade to (NONE releases fully, SHARED keeps a reader lock)
* @return result indicating success and the current lock level held by the caller
*/
LockOperationResult unlock(const std::string& resourceId, const std::string& uuid, LockLevel lockLevel);

/**
* Checks whether any connection (including the caller) holds a RESERVED or higher lock on the resource.
*
* @param resourceId identifier of the resource to check
* @param uuid caller-unique identifier
* @return true if a RESERVED or higher lock exists, false otherwise
*/
bool checkReservedLock(const std::string& resourceId, const std::string& uuid);

private:
LockApi(const std::shared_ptr<LockApiImpl>& impl);
};

} // namespace lock
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_LOCK_LOCKAPI_HPP_
Loading