# ppconsul
**Repository Path**: fanxinkeji_admin/ppconsul
## Basic Information
- **Project Name**: ppconsul
- **Description**: No description available
- **Primary Language**: C++
- **License**: BSL-1.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-08-24
- **Last Updated**: 2025-08-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Ppconsul
*Version 0.2*
A C++ client library for [Consul](http://consul.io). Consul is a distributed tool for discovering and configuring services in your infrastructure.
The goal of Ppconsul is to:
* Fully cover version 1 of Consul [HTTP API](http://www.consul.io/docs/agent/http.html). Please check the current [implementation status](status.md).
* Provide simple, modular and effective API based on C++11.
* Support different platforms. At the moment, Linux, Windows and macOS platforms supported.
* Cover all the code with automated tests.
Note that this project is under development and doesn't promise a stable interface.
Library tests are currently running against **Consul v1.11.1**. Library is known to work with Consul starting from version **0.4** (earlier versions might work as well but has never been tested) although some tests fail for older versions because of backward incompatible changes in Consul.
The library is written in C++11 and requires a quite modern compiler. Currently it's compiled with:
* macOS: Clang 11 (Xcode 11.3.1)
* Ubuntu Linux: GCC 7.4 with stdlibc++
* Windows: n/a
Oldest versions of compilers that should work (all with using C++11 standard)
- Clang 5
- GCC 4.8
- Visual Studio 2013
I try to support all modern compilers and platforms but I don't have resources to do extensive testing so from time to time something got broken on some platforms (mostly old GCC or Windows issues). Please create an issue if you discover a compilation error on your platform.
The library depends on:
* [git](https://git-scm.com/) (optional) to deduce correct .so version
* [Boost](http://www.boost.org/) 1.55 or later. Ppconsul needs only headers with one exception: using of GCC 4.8 requires Boost.Regex library because [regular expressions are broken in GCC 4.8](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631).
* [libCURL](http://curl.haxx.se/libcurl/) to do HTTP/HTTPS.
The library includes code of the following 3rd party libraries (check `ext` directory):
* [json11](https://github.com/dropbox/json11) library to deal with JSON.
* [libb64](http://libb64.sourceforge.net/) library for base64 decoding.
For unit tests, the library uses [Catch2](https://github.com/catchorg/Catch2) framework. Many thanks to Phil Nash for this great product.
## Warm Up Examples
### Register, deregister and report the state of your service in Consul:
```cpp
#include "ppconsul/agent.h"
using ppconsul::Consul;
using namespace ppconsul::agent;
// Create a consul client that uses default local endpoint `http://127.0.0.1:8500` and default data center
Consul consul;
// We need the 'agent' endpoint for a service registration
Agent agent(consul);
// Register a service with associated HTTP check:
agent.registerService(
kw::name = "my-service",
kw::port = 9876,
kw::tags = {"tcp", "super_server"},
kw::check = HttpCheck{"http://localhost:80/", std::chrono::seconds(2)}
);
...
// Unregister service
agent.deregisterService("my-service");
...
// Register a service with TTL
agent.registerService(
kw::name = "my-service",
kw::port = 9876,
kw::id = "my-service-1",
kw::check = TtlCheck{std::chrono::seconds(5)}
);
// Report service is OK
agent.servicePass("my-service-1");
// Report service is failed
agent.serviceFail("my-service-1", "Disk is full");
```
### Determine raft leader (or lack thereof) and raft peers:
```cpp
#include "ppconsul/status.h"
using ppconsul::Consul;
using namespace ppconsul::status;
// Create a consul client that uses default local endpoint `http://127.0.0.1:8500` and default data center
Consul consul;
// We need the status endpoint
Status status(consul);
// Determine whether a leader has been elected
bool isLeaderElected = status.isLeaderElected();
// Determine the actual raft leader
auto leader = status.leader();
// Determine the raft peers
auto peers = status.peers();
```
### Use Key-Value storage:
```cpp
#include "ppconsul/kv.h"
using ppconsul::Consul;
using ppconsul::Consistency;
using namespace ppconsul::kv;
Consul consul;
// We need the 'kv' endpoint
Kv kv(consul);
// Read the value of a key from the storage
std::string something = kv.get("settings.something", "default-value");
// Read the value of a key from the storage with consistency mode specified
something = kv.get("settings.something", "default-value", kw::consistency = Consistency::Consistent);
// Erase a key from the storage
kv.erase("settings.something-else");
// Set the value of a key
kv.set("settings.something", "new-value");
```
### Blocking query to Key-Value storage:
```cpp
// Get key+value+metadata item
KeyValue item = kv.item("status.last-event-id");
// Wait for the item change for no more than 1 minute:
item = kv.item("status.last-event-id", kw::block_for = {std::chrono::minutes(1), item.modifyIndex});
// If key exists, print it:
if (item)
std::cout << item.key << "=" << item.value << "\n";
```
### Abort all [blocking] queries:
```cpp
Consul consul(kw::enable_stop = true); // Must be enabled at construction time
Kv kv(consul);
// Issue blocking queries, similarly to example above, on background threads etc.
// Stop all pending requests, e.g. at shutdown. No further requests can be done after this call.
consul.stop();
```
Call to `Consul::stop()` is irreversible: once it's done the `Consul` object is switched to the stopped state forever. This whole feature purpose is to gracefully abort ongoing blocking queries on application/component shutdown.
### Configure connect and request timeouts
By default, connect timeout is set to 5 seconds and request timeout is not set (so it is unlimited). If needed you can override default values as following:
```cpp
#include "ppconsul/consul.h"
using namespace ppconsul;
Consul consul("https://localhost:8080",
kw::connect_timeout = std::chrono::milliseconds{15000}
kw::request_timeout = std::chrono::milliseconds{5000});
// Use consul ...
```
If you're using blocking queries then make sure that request timeout is longer than block interval, otherwise request will fail with timeout error.
### Connect to Consul via HTTPS (TLS/SSL, whatever you call it):
```cpp
#include "ppconsul/consul.h"
using namespace ppconsul;
Consul consul("https://localhost:8080",
kw::tls::cert="path/to/cert",
kw::tls::key="path/to/private/key",
kw::tls::ca_info="path/to/ca/cert");
// Use consul ...
```
## Multi-Threaded Usage of Ppconsul
Each Consul object has a pool of HTTP(S) clients to perform network requests. It is safe to call any endpoint (e.g. `Kv`, `Agent` etc) object or Consul object from multiple threads in the same time.
Call to `Consul::stop()` method stops all ongoing requests on that particular `Consul` object.
## Multi-Threaded Usage of Ppconsul and libCURL initialization
libCURL requires that global initialization function [`curl_global_init`](https://curl.se/libcurl/c/curl_global_init.html) is called before any oither libCURL function is called and before any additional thread is started.
Ppconsul calls `curl_global_init` for you at the moment when `makeDefaultHttpClientFactory()` is called for the first time which is usually done when first `Consul` object is created. If this is too late then you need to call to `curl_global_init` and `curl_global_cleanup` at the right moment yourself, similar to this example:
```cpp
int main(int argc, char *argv[])
{
curl_global_init(CURL_GLOBAL_DEFAULT | CURL_GLOBAL_SSL);
// Existing code that uses Ppconsul and starts extra threads...
curl_global_cleanup();
return 0;
}
```
`CURL_GLOBAL_SSL` flag is only needed if your're using HTTPS (TLS/SSL).
If your application needs to exclusively control libCURL initialization then you m ay want to skip libCURL initialization in Ppconsul's default HttpClientFactory. To do this, create default HttpClientFactory explicitly via `makeDefaultHttpClientFactory(false)` and pass it to `Consul`:
```cpp
Consul consul(makeDefaultHttpClientFactory(false), ...);
```
## Custom `http::HttpClient`
If needed, user can implement `http::HttpClient` interface and pass custom `HttpClientFactory` to `Consul`'s constructor.
## Documentation
TBD
## How To Build
You need C++11 compatible compiler (see above for the list of supported compilers) and [CMake](http://www.cmake.org/) 3.1 or above.
### TLDR
```bash
# Install dependencies
conan install .
# Make workspace directory
mkdir workspace
cd workspace
# Configure:
cmake ..
#Build
cmake --build . --config Release
# Install
cmake --build . --config Release --target install
```
### Get dependencies
If you use [Conan](https://conan.io/) then simply run `conan install .` to install dependencies.
Otherwise:
* Install [git](https://git-scm.com/) (any version should be fine)
* Install [Boost](http://www.boost.org/) 1.55 or later. You need compiled Boost.Regex library if you use GCC 4.8, otherwise you need headers only.
* Install [libCURL](http://curl.haxx.se/libcurl/) (any version should be fine).
### Build
Configure project:
```bash
mkdir workspace
cd workspace
cmake ..
```
You may want to set the following CMake variables on the command line:
To change where CMake looks for Boost, pass `-DBOOST_ROOT=` parameter to CMake or set `BOOST_ROOT` environment variable.
To change where CMake looks for libCURL, pass `-DCURL_ROOT=` parameter to CMake or set `CURL_ROOT` environment variable.
To change default install location, pass `-DCMAKE_INSTALL_PREFIX=` parameter.
To build Ppconsul as static library, pass `-DBUILD_STATIC_LIB=ON` parameter.
Note that in this case you have to link with json11 static library as well (json11 library is build as part of Ppconsul build.)
**Note that on Windows Ppconsul can only be built as static library (that's default mode on Windows), see issue [Allow to build Ppconsul as dynamic library on Windows](https://github.com/oliora/ppconsul/issues/25)**.
*Note about -G option of CMake to choose you favourite IDE to generate project files for.*
Build:
```bash
cmake --build . --config Release
```
If Makefile generator was used then you can also do:
```bash
make
```
## How to Install
Build it first as described above then run
```bash
cmake --build . --config Release --target install
```
If Makefile generator was used then you can also do:
```bash
make install
```
## How To Run Tests
Install [Consul](http://consul.io) 0.4 or newer. *I recommend 0.7 or newer since it's easier to run it in development mode.*
### Run Consul
For Consul 0.9 and above:
```bash
consul agent -dev -datacenter=ppconsul_test -enable-script-checks=true
```
For Consul 0.7 and 0.8:
```bash
consul agent -dev -datacenter=ppconsul_test
```
For earlier version of Consul follow its documentation on how to run it with `ppconsul_test` datacenter.
### Run Tests
```bash
ctest -C Release
```
If Makefile generator was used then you can also do:
```bash
make test
```
There are the following environment variable to configure tests:
|Name|Default Value|Description|
|----|-------------|-----------|
|`PPCONSUL_TEST_ADDR`|"127.0.0.1:8500"|The Consul network address|
|`PPCONSUL_TEST_DC`|"ppconsul_test"|The Consul datacenter|
|`PPCONSUL_TEST_LEADER_ADDR`|"127.0.0.1:8300"|The Consul raft leader address|
**Never set `PPCONSUL_TEST_DC` into a datacenter that you can't throw away because Ppconsul tests will screw it up in many different ways.**
### Known Problems
Sometimes catalog tests failed on assertion `REQUIRE(index1 == resp1.headers().index());`. In this case, just rerun the tests.
The reason for the failure is Consul's internal idempotent write which cause a spurious wakeup of waiting blocking query. Check the critical note under the blocking queries documentation at https://www.consul.io/docs/agent/http.html.
## How to Use Ppconsul in Your Project
Build and install it first as described above.
When installed, the library can be simply used in any CMake-based project as following:
```
find_package(ppconsul)
add_executable( ...)
target_link_libraries( ppconsul)
```
As an alternative you can clone ppconsul into your project as submodule:
```
git submodule add https://github.com/oliora/ppconsul.git
```
And then include it into your CMake-based project as subdirectory:
```
set(BUILD_TESTS OFF)
set(BUILD_STATIC_LIB ON)
add_subdirectory(ppconsul)
...
target_link_libraries( ppconsul)
```
## Found a bug? Got a feature request? Need help with Ppconsul?
Use [issue tracker](https://github.com/oliora/ppconsul/issues) or/and drop an email to [oliora](https://github.com/oliora).
## Contribute
First of all, welcome on board!
To contribute, please fork this repo, make your changes and create a pull request.
## License
The library released under [Boost Software License v1.0](http://www.boost.org/LICENSE_1_0.txt).