Skip to content

Commit

Permalink
Merge pull request #83 from tgockel/issue/53/doc-results
Browse files Browse the repository at this point in the history
doc: Adds and rewrites documentation to be readable and complete.
  • Loading branch information
tgockel authored Mar 2, 2018
2 parents 6082e97 + 211c046 commit 92470a0
Show file tree
Hide file tree
Showing 21 changed files with 1,010 additions and 828 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,7 @@ In the Java API, the `ZooKeeper` client allows for a global
[Watcher](https://zookeeper.apache.org/doc/r3.4.10/api/org/apache/zookeeper/Watcher.html).
In the C API, `zookeeper_init` can be provided with a global function with the signature
`void (*)(zhandle_t* zh, int type, int state, const char* path, void* watcherCtx)` to achieve this same result.
The ZooKeeper community considers global watches as "legacy" and prefers the use of watcher objects set on a per-path
basis.
Global watches are somewhat of a "legacy" feature -- the dual interface of global and callbacks is somewhat confusing.
As such, global watches are *not* supported by this library.

### Synchronous API
Expand Down
144 changes: 88 additions & 56 deletions src/zk/acl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@
namespace zk
{

/** \addtogroup Client
* \{
**/
/// \addtogroup Client
/// \{

/** Describes the ability of a user to perform a certain action. Permissions can be mixed together like integers with
* \c | and \c &.
**/
/// Describes the ability of a user to perform a certain action. Permissions can be mixed together like integers with
/// \c | and \c &.
enum class permission : unsigned int
{
none = 0b00000, //!< No permissions are set (server could have been configured without ACL support).
Expand All @@ -31,27 +29,28 @@ enum class permission : unsigned int
all = 0b11111, //!< You can do anything.
};

/// Set union operation of \ref permission.
constexpr permission operator|(permission a, permission b)
{
return permission(static_cast<unsigned int>(a) | static_cast<unsigned int>(b));
}

/// Set intersection operation of \ref permission.
constexpr permission operator&(permission a, permission b)
{
return permission(static_cast<unsigned int>(a) & static_cast<unsigned int>(b));
}

/// Set inverse operation of \ref permission. This is not exactly the bitwise complement of \a a, as the returned value
/// will only include bits set that are valid in \ref permission discriminants.
constexpr permission operator~(permission a)
{
return permission(~static_cast<unsigned int>(a));
return permission(~static_cast<unsigned int>(a)) & permission::all;
}

/** Check that \a self allows it \a perform all operations. For example,
* `allows(permission::read | permission::write, permission::read)` will be \c true, as `read|write` is allowed to
* \c read.
*
* \relates permission
**/
/// Check that \a self allows it \a perform all operations. For example,
/// `allows(permission::read | permission::write, permission::read)` will be \c true, as `read|write` is allowed to
/// \c read.
constexpr bool allows(permission self, permission perform)
{
return (self & perform) == perform;
Expand All @@ -61,50 +60,47 @@ std::ostream& operator<<(std::ostream&, const permission&);

std::string to_string(const permission&);

/** An individual rule in an \c acl. It consists of a \c scheme and \c id pair to identify the \e who and a
* \c permission set to determine what they are allowed to do.
*
* See <a href="https://zookeeper.apache.org/doc/r3.4.10/zookeeperProgrammers.html#sc_ACLPermissions">"Builtin ACL
* Schemes"</a> in the ZooKeeper Programmer's Guide for more information.
**/
/// An individual rule in an \ref acl. It consists of a \ref scheme and \ref id pair to identify the who and a
/// \ref permission set to determine what they are allowed to do.
///
/// See <a href="https://zookeeper.apache.org/doc/r3.4.10/zookeeperProgrammers.html#sc_ACLPermissions">"Builtin ACL
/// Schemes"</a> in the ZooKeeper Programmer's Guide for more information.
class acl_rule final
{
public:
/** Create an ACL under the given \a scheme and \a id with the given \a permissions. **/
/// Create an ACL under the given \a scheme and \a id with the given \a permissions.
acl_rule(std::string scheme, std::string id, permission permissions);

~acl_rule() noexcept;

/** The authentication scheme this list is used for. The most common scheme is `"auth"`, which allows any
* authenticated user to perform actions (see \c acls::creator_all).
*
* ZooKeeper's authentication system is extensible, but the majority of use cases are covered by the built-in
* schemes:
*
* - \c "world" -- This has a single ID \c "anyone" that represents any user of the system. The ACLs
* \ref acls::open_unsafe and \ref acls::read_unsafe use the \c "world" scheme.
* - \c "auth" -- This represents any authenticated user. The \c id field is unused. The ACL \ref acls::creator_all
* uses the \c "auth" scheme.
* - \c "digest" -- This uses a \c "${username}:${password}" string to generate MD5 hash which is then used as an
* identity. Authentication is done by sending the string in clear text. When used in the ACL, the expression
* will be the \c "${username}:${digest}", where \c digest is the base 64 encoded SHA1 digest of \c password.
* - \c "ip" -- This uses the client host IP as an identity. The \c id expression is an IP address or CIDR netmask,
* which will be matched against the client identity.
**/
/// The authentication scheme this list is used for. The most common scheme is `"auth"`, which allows any
/// authenticated user to perform actions (see \ref acls::creator_all).
///
/// ZooKeeper's authentication system is extensible, but the majority of use cases are covered by the built-in
/// schemes:
///
/// - \c "world" -- This has a single ID \c "anyone" that represents any user of the system. The ACLs
/// \ref acls::open_unsafe and \ref acls::read_unsafe use the \c "world" scheme.
/// - \c "auth" -- This represents any authenticated user. The \c id field is unused. The ACL \ref acls::creator_all
/// uses the \c "auth" scheme.
/// - \c "digest" -- This uses a \c "${username}:${password}" string to generate MD5 hash which is then used as an
/// identity. Authentication is done by sending the string in clear text. When used in the ACL, the expression
/// will be the \c "${username}:${digest}", where \c digest is the base 64 encoded SHA1 digest of \c password.
/// - \c "ip" -- This uses the client host IP as an identity. The \c id expression is an IP address or CIDR netmask,
/// which will be matched against the client identity.
const std::string& scheme() const
{
return _scheme;
}

/** The ID of the user under the \c scheme. For example, with the \c "ip" \c scheme, this is an IP address or CIDR
* netmask.
**/
/// The ID of the user under the \ref scheme. For example, with the \c "ip" \c scheme, this is an IP address or CIDR
/// netmask.
const std::string& id() const
{
return _id;
}

/** The permissions associated with this ACL. **/
/// The permissions associated with this ACL.
const permission& permissions() const
{
return _permissions;
Expand All @@ -116,7 +112,8 @@ class acl_rule final
permission _permissions;
};

std::size_t hash(const acl_rule&);
/// Compute a hash for the given \a rule.
std::size_t hash(const acl_rule& rule);

[[gnu::pure]] bool operator==(const acl_rule& lhs, const acl_rule& rhs);
[[gnu::pure]] bool operator!=(const acl_rule& lhs, const acl_rule& rhs);
Expand All @@ -129,14 +126,16 @@ std::ostream& operator<<(std::ostream&, const acl_rule&);

std::string to_string(const acl_rule&);

/** An access control list is a wrapper around \c acl_rule instances. In general, the ACL system is similar to UNIX file
* access permissions, where znodes act as files. Unlike UNIX, each znode can have any number of ACLs to correspond
* with the potentially limitless (and pluggable) authentication schemes. A more surprising difference is that ACLs are
* not recursive: If \c /path is only readable by a single user, but \c /path/sub is world-readable, then anyone will
* be able to read \c /path/sub.
*
* \see https://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#sc_ZooKeeperAccessControl
**/
/// An access control list is a wrapper around \ref acl_rule instances. In general, the ACL system is similar to UNIX
/// file access permissions, where znodes act as files. Unlike UNIX, each znode can have any number of ACLs to
/// correspond with the potentially limitless (and pluggable) authentication schemes. A more surprising difference is
/// that ACLs are not recursive: If \c /path is only readable by a single user, but \c /path/sub is world-readable, then
/// anyone will be able to read \c /path/sub.
///
/// See <a href="https://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#sc_ZooKeeperAccessControl">ZooKeeper
/// Programmer's Guide</a> for more information.
///
/// \see acls
class acl final
{
public:
Expand All @@ -145,36 +144,68 @@ class acl final
using size_type = std::size_t;

public:
/// Create an empty ACL. Keep in mind that an empty ACL is an illegal ACL.
acl() = default;

/// Create an instance with the provided \a rules.
acl(std::vector<acl_rule> rules) noexcept;

/// Create an instance with the provided \a rules.
acl(std::initializer_list<acl_rule> rules) :
acl(std::vector<acl_rule>(rules))
{ }

~acl() noexcept;

/// The number of rules in this ACL.
size_type size() const { return _impl.size(); }

/// \{
/// Get the rule at the given \a idx.
const acl_rule& operator[](size_type idx) const { return _impl[idx]; }

acl_rule& operator[](size_type idx) { return _impl[idx]; }
/// \}

/// \{
/// Get the rule at the given \a idx.
///
/// \throws std::out_of_range if the \a idx is larger than \ref size.
const acl_rule& at(size_type idx) const { return _impl.at(idx); }
acl_rule& at(size_type idx) { return _impl.at(idx); }
/// \}

/// \{
/// Get an iterator to the beginning of the rule list.
iterator begin() { return _impl.begin(); }
const_iterator begin() const { return _impl.begin(); }
const_iterator cbegin() const { return _impl.begin(); }
/// \}

/// \{
/// Get an iterator to the end of the rule list.
iterator end() { return _impl.end(); }
const_iterator end() const { return _impl.end(); }
const_iterator cend() const { return _impl.end(); }
/// \}

void reserve(size_type sz) { _impl.reserve(sz); }
/// Increase the reserved memory block so it can store at least \a capacity rules without reallocating.
void reserve(size_type capacity) { _impl.reserve(capacity); }

/// Construct a rule emplace on the end of the list using \a args.
///
/// \see push_back
template <typename... TArgs>
void emplace_back(TArgs&&... args)
{
_impl.emplace_back(std::forward<TArgs>(args)...);
}

/// \{
/// Add the rule \a x to the end of this list.
void push_back(acl_rule&& x) { emplace_back(std::move(x)); }
void push_back(const acl_rule& x) { emplace_back(x); }
/// \}

private:
std::vector<acl_rule> _impl;
};
Expand All @@ -186,21 +217,22 @@ std::ostream& operator<<(std::ostream&, const acl&);

std::string to_string(const acl& self);

/** Convenience operations around commonly-used ACLs. **/
/// Commonly-used ACLs.
class acls
{
public:
/** This ACL gives the creators authentication id's all permissions. **/
/// This ACL gives the creators authentication id's all permissions.
static const acl& creator_all();

/** This is a completely open ACL. **/
/// This is a completely open ACL. It is also the ACL used in operations like \ref client::create if no ACL is
/// specified.
static const acl& open_unsafe();

/** This ACL gives the world the ability to read. **/
/// This ACL gives the world the ability to read.
static const acl& read_unsafe();
};

/** \} **/
/// \}

}

Expand Down
62 changes: 32 additions & 30 deletions src/zk/buffer.hpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
/** \file
* Controls the \c buffer type.
**/
/// \file
/// Controls the \c buffer type.
#pragma once

#include <zk/config.hpp>

#include <type_traits>

/** \addtogroup Client
* \{
**/
/// \addtogroup Client
/// \{

/** \def ZKPP_BUFFER_USE_CUSTOM
* Set this to 1 to use a custom definitions for \c zk::buffer. If this is set, you must also set
* \c ZKPP_BUFFER_INCLUDE and \c ZKPP_BUFFER_TYPE.
**/
/// \def ZKPP_BUFFER_USE_CUSTOM
/// Set this to 1 to use a custom definitions for \c buffer. If this is set, you must also set
/// \ref ZKPP_BUFFER_INCLUDE and \ref ZKPP_BUFFER_TYPE.
///
/// \def ZKPP_BUFFER_INCLUDE
/// The header file to use to find the \c buffer type. This value is set automatically if using built-in configuration
/// options (such as \ref ZKPP_BUFFER_USE_STD_VECTOR) and must be set manually if using \ref ZKPP_BUFFER_USE_CUSTOM.
///
/// \def ZKPP_BUFFER_TYPE
/// The type name to use for the \c buffer type. This value is set automatically if using built-in configuration
/// options (such as \ref ZKPP_BUFFER_USE_STD_VECTOR) and must be set manually if using \ref ZKPP_BUFFER_USE_CUSTOM.
#ifndef ZKPP_BUFFER_USE_CUSTOM
# define ZKPP_BUFFER_USE_CUSTOM 0
#endif

/** \def ZKPP_BUFFER_USE_STD_VECTOR
* Set this to 1 to use \c std::vector<char> for the implementation of \c zk::buffer. This is the default behavior.
**/
/// \def ZKPP_BUFFER_USE_STD_VECTOR
/// Set this to 1 to use \c std::vector<char> for the implementation of \ref zk::buffer. This is the default behavior.
#ifndef ZKPP_BUFFER_USE_STD_VECTOR
# if ZKPP_BUFFER_USE_CUSTOM
# define ZKPP_BUFFER_USE_STD_VECTOR 0
Expand All @@ -41,29 +45,27 @@
# error "Unknown type to use for zk::buffer"
#endif

/** \} **/
/// \}

#include ZKPP_BUFFER_INCLUDE

namespace zk
{

/** \addtogroup Client
* \{
**/
/// \addtogroup Client
/// \{

/** The \c buffer type. By default, this is an \c std::vector<char>, but this can be altered by compile-time flags such
* as \c ZKPP_BUFFER_USE_CUSTOM. The requirements for a custom buffer are minimal -- the type must fit this criteria:
*
* | expression | type | description |
* |:----------------------|:--------------------------|:-------------------------------------------------------------|
* | `buffer::value_type` | `char` | Buffers must be made of single-byte elements |
* | `buffer::size_type` | `std::size_t` | |
* | `buffer(ib, ie)` | `buffer` | Constructs a buffer with the range [`ib`, `ie`) |
* | `buffer(buffer&&)` | `buffer` | Move constructible. |
* | `size()` | `size_type` | Get the length of the buffer |
* | `data()` | `const value_type*` | Get a pointer to the beginning of the contents |
**/
/// The \c buffer type. By default, this is an \c std::vector<char>, but this can be altered by compile-time flags such
/// as \ref ZKPP_BUFFER_USE_CUSTOM. The requirements for a custom buffer are minimal -- the type must fit this criteria:
///
/// | expression | type | description |
/// |:----------------------|:--------------------------|:-------------------------------------------------------------|
/// | `buffer::value_type` | `char` | Buffers must be made of single-byte elements |
/// | `buffer::size_type` | `std::size_t` | |
/// | `buffer(ib, ie)` | `buffer` | Constructs a buffer with the range [`ib`, `ie`) |
/// | `buffer(buffer&&)` | `buffer` | Move constructible. |
/// | `size()` | `size_type` | Get the length of the buffer |
/// | `data()` | `const value_type*` | Get a pointer to the beginning of the contents |
using buffer = ZKPP_BUFFER_TYPE;

// Check through static_assert:
Expand All @@ -82,6 +84,6 @@ static_assert(std::is_constructible<ptr<const buffer::value_type>,
"buffer::data() must return ptr<const buffer::value_type>"
);

/** \} **/
/// \}

}
11 changes: 10 additions & 1 deletion src/zk/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace zk
// client //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

client::client(const connection_params& params) :
client(connection::connect(params))
{ }

client::client(string_view conn_string) :
client(connection::connect(conn_string))
{ }
Expand All @@ -22,10 +26,15 @@ client::client(std::shared_ptr<connection> conn) noexcept :
{ }

future<client> client::connect(string_view conn_string)
{
return connect(connection_params::parse(conn_string));
}

future<client> client::connect(connection_params conn_params)
{
try
{
auto conn = connection::connect(conn_string);
auto conn = connection::connect(conn_params);
auto state_change_fut = conn->watch_state();
if (conn->state() == state::connected)
{
Expand Down
Loading

0 comments on commit 92470a0

Please sign in to comment.