Giter Site home page Giter Site logo

tdv / redis-cpp Goto Github PK

View Code? Open in Web Editor NEW
113.0 12.0 31.0 72 KB

redis-cpp is a header-only library in C++17 for Redis (and C++11 backport)

License: MIT License

C++ 77.17% CMake 20.38% Dockerfile 0.73% Shell 0.25% C 1.46%
redis-client cpp17 resp-serialization cpp11

redis-cpp's Introduction

redis-cpp - lightweight C++ client library for Redis

redis-cpp is a C++17 library for executing Redis commands with support for pipelines and the publish / subscribe pattern. Moreover, you can extend the library with your own stream implementation to communicate with Redis. You can also use it like a RESP serializer (pure core). You need only know a couple of functions to start working with Redis.

// Connect to server
auto stream = rediscpp::make_stream("localhost", "6379");
// Execute command
std::cout << rediscpp::execute(*stream, "ping").as<std::string>() << std::endl;

And you may dive deeper if you feel the need.

NOTE
If you need a C++11 version you could switch to c++11 branch and use that one.

Version

1.1.0

Features

  • easy way to access Redis
  • pipelines
  • publish / subscribe
  • pure core in C++ for the RESP
  • extensible transport
  • header-only library if it's necessary
  • minimal dependencies
  • various levels of usage

License

Distributed under the MIT License

Compiler and OS

This has compiled and tested within gcc 9.3 and clang 10.0 on Ubuntu 20.04.
You might try other compiler or OS.

NOTE
All code is a cross-platform.

Dependencies

  • Boost (at least 1.71 only for using with built-in implementation of transport).

Build and install

Build library

git clone https://github.com/tdv/redis-cpp.git  
cd redis-cpp
mkdir build  
cd build  
cmake ..  
make  
make install  

You can use CMAKE_INSTALL_PREFIX to select the installation directory
Moreover, you can use cmake options to configure the library for header-only or pure core.
Instead of cmake options, you can define REDISCPP_HEADER_ONLY and use the library as header-only without any cmake file.

NOTE
redis-cpp has two build options

  • Pure core only
  • Header-only

Use cmake -D with REDISCPP_HEADER_ONLY or REDISCPP_PURE_CORE. You can enable both options at the same time.
You can use your own transport with the 'pure core' option.

If you need to use the header-only library, you can copy the folder redis-cpp from include/redis-cpp in your project and define the macro REDISCPP_HEADER_ONLY before including the redis-cpp headers following the example code below:

#define REDISCPP_HEADER_ONLY
#include <redis-cpp/stream.h>
#include <redis-cpp/execute.h>

// Include something else

Build examples

cd examples/{example_project}
mkdir build  
cd build  
cmake ..  
make  

Examples

NOTE
Look at the redis-docker folder to get all you need to start testing redis-cpp. There are files to build and run a Redis server in Docker.

Ping

Source code
Description
The "Ping" example demonstrates how to execute a Redis command.

// STD
#include <cstdlib>
#include <iostream>

#include <redis-cpp/stream.h>
#include <redis-cpp/execute.h>

int main()
{
    try
    {
        auto stream = rediscpp::make_stream("localhost", "6379");
        auto response = rediscpp::execute(*stream, "ping");
        std::cout << response.as<std::string>() << std::endl;
    }
    catch (std::exception const &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Set and Get data

Source code
Description
The example demonstrates how to set and get a value.

// STD
#include <cstdlib>
#include <iostream>

#include <redis-cpp/stream.h>
#include <redis-cpp/execute.h>

int main()
{
    try
    {
        auto stream = rediscpp::make_stream("localhost", "6379");

        auto const key = "my_key";

        auto response = rediscpp::execute(*stream, "set",
                key, "Some value for 'my_key'", "ex", "60");

        std::cout << "Set key '" << key << "': " << response.as<std::string>() << std::endl;

        response = rediscpp::execute(*stream, "get", key);
        std::cout << "Get key '" << key << "': " << response.as<std::string>() << std::endl;
    }
    catch (std::exception const &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Pipeline

Source code
Description
It's a more complicated example which demonstrates how to use a pipeline within Redis to achieve better performance.

// STD
#include <cstdlib>
#include <iostream>

#include <redis-cpp/stream.h>
#include <redis-cpp/execute.h>

int main()
{
    try
    {
        auto stream = rediscpp::make_stream("localhost", "6379");

        int const N = 10;
        auto const key_pref = "my_key_";

        // Executing command 'SET' N times without getting any response
        for (int i = 0 ; i < N ; ++i)
        {
            auto const item = std::to_string(i);
            rediscpp::execute_no_flush(*stream,
                "set", key_pref + item, item , "ex", "60");
        }

        // Flush all
        std::flush(*stream);

        // Getting response for each sent 'SET' request
        for (int i = 0 ; i < N ; ++i)
        {
            rediscpp::value value{*stream};
            std::cout << "Set " << key_pref << i << ": "
                      << value.as<std::string_view>() << std::endl;
        }

        // Executing command 'GET' N times without getting any response
        for (int i = 0 ; i < N ; ++i)
        {
            rediscpp::execute_no_flush(*stream, "get",
                key_pref + std::to_string(i));
        }

        // Flush all
        std::flush(*stream);

        // Getting response for each sent 'GET' request
        for (int i = 0 ; i < N ; ++i)
        {
            rediscpp::value value{*stream};
            std::cout << "Get " << key_pref << i << ": "
                      << value.as<std::string_view>() << std::endl;
        }
    }
    catch (std::exception const &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Resp

Source code
Description
The "Resp" example demonstrates a basic RESP serialization within redis-cpp without communication with Redis server. It's meant to show you how to use RESP serialization with redis-cpp library.

// STD
#include <cstdlib>
#include <iostream>
#include <sstream>

#include <redis-cpp/execute.h>

namespace resps = rediscpp::resp::serialization;
namespace respds = rediscpp::resp::deserialization;

auto make_sample_data()
{
    std::ostringstream stream;

    put(stream, resps::array{
            resps::simple_string{"This is a simple string."},
            resps::error_message{"This is an error message."},
            resps::bulk_string{"This is a bulk string."},
            resps::integer{100500},
            resps::array{
                resps::simple_string("This is a simple string in a nested array."),
                resps::bulk_string("This is a bulk string in a nested array.")
            }
        });

    return stream.str();
}

void print_value(respds::array::item_type const &value, std::ostream &stream)
{
    std::visit(rediscpp::resp::detail::overloaded{
            [&stream] (respds::simple_string const &val)
            { stream << "Simple string: " << val.get() << std::endl; },
            [&stream] (respds::error_message const &val)
            { stream << "Error message: " << val.get() << std::endl; },
            [&stream] (respds::bulk_string const &val)
            { stream << "Bulk string: " << val.get() << std::endl; },
            [&stream] (respds::integer const &val)
            { stream << "Integer: " << val.get() << std::endl; },
            [&stream] (respds::array const &val)
            {
                stream << "----- Array -----" << std::endl;
                for (auto const &i : val.get())
                    print_value(i, stream);
                stream << "-----------------" << std::endl;
            },
            [&stream] (auto const &)
            { stream << "Unexpected value type." << std::endl; }
        }, value);
}

void print_sample_data(std::istream &istream, std::ostream &ostream)
{
    rediscpp::value value{istream};
    print_value(value.get(), ostream);
}

int main()
{
    try
    {
        auto const data = make_sample_data();
        std::cout << "------------ Serialization ------------" << std::endl;
        std::cout << data << std::endl;

        std::cout << "------------ Deserialization ------------" << std::endl;
        std::istringstream stream{data};
        print_sample_data(stream, std::cout);
        std::cout << std::endl;
    }
    catch (std::exception const &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Publish / Subscribe

Source code
Description
This is a more complicated example within redis-cpp which demonstrates how to publish messages and create a subscription to a queue. In the example a publisher and subscriber located in one process simultaniously, each one has its own stream to communicate with Redis. Usually, in real projects the publisher and subscriber are not located in one process.

// STD
#include <cstdlib>
#include <iostream>
#include <thread>

// BOOST
#include <boost/thread.hpp>

#include <redis-cpp/stream.h>
#include <redis-cpp/execute.h>

int main()
{
    try
    {
        auto const N = 100;
        auto const queue_name = "test_queue";

        bool volatile stopped = false;

        // A message printer. The message from a queue.
        auto print_message = [] (auto const &value)
        {
            using namespace rediscpp::resp::deserialization;
            std::visit(rediscpp::resp::detail::overloaded{
                   [] (bulk_string const &val)
                   { std::cout << val.get() << std::endl; },
                   [] (auto const &)
                   { std::cout << "Unexpected value type." << std::endl; }
               }, value);
        };

        // The subscriber is run in its own thread.
        // It's some artificial example, when publisher
        // and subscriber are working in one process.
        // It's only for demonstration library abilities.
        boost::thread subscriber{
            [&stopped, &queue_name, &print_message]
            {
                // Its own stream for a subscriber
                auto stream = rediscpp::make_stream("localhost", "6379");
                auto response = rediscpp::execute(*stream, "subscribe", queue_name);
                // An almost endless loop for getting messages from the queues.
                while (!stopped)
                {
                    // Reading / waiting for a message.
                    rediscpp::value value{*stream};
                    // Message extraction.
                    std::visit(rediscpp::resp::detail::overloaded{
                            // We're wondered only an array in response.
                            // Otherwise, there is an error.
                            [&print_message] (rediscpp::resp::deserialization::array const &arr)
                            {
                                std::cout << "-------- Message --------" << std::endl;
                                for (auto const &i : arr.get())
                                    print_message(i);
                                std::cout << "-------------------------" << std::endl;
                            },
                            // Oops. An error in a response.
                            [] (rediscpp::resp::deserialization::error_message const &err)
                            { std::cerr << "Error: " << err.get() << std::endl; },
                            // An unexpected response.
                            [] (auto const &)
                            { std::cout << "Unexpected value type." << std::endl; }
                        }, value.get());
                }
            }
        };

        // An artificial delay. It's not necessary in real code.
        std::this_thread::sleep_for(std::chrono::milliseconds{200});

        // Its own stream for a publisher.
        auto stream = rediscpp::make_stream("localhost", "6379");

        // The publishing N messages.
        for (int i = 0 ; i < N ; ++i)
        {
            auto response = rediscpp::execute(*stream,
                    "publish", queue_name, std::to_string(i));
            std::cout << "Delivered to " << response.as<std::int64_t>()
                      << " subscribers." << std::endl;
        }

        // An artificial delay. It's not necessary in real code.
        // It's due to the artificiality of the example,
        // where everything is in one process.
        std::this_thread::sleep_for(std::chrono::milliseconds{200});

        stopped = true;
        std::this_thread::sleep_for(std::chrono::milliseconds{200});
        // Why not?... Please, avoid it in real code.
        // It's justified only in examples.
        subscriber.interrupt();
    }
    catch (std::exception const &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Conclusion

Take a look at a code above one more time. I hope you can find something useful for your own projects with Redis. I'd thought about adding one more level to wrap all Redis commands and refused this idea. A lot of useless work with a small outcome, because, in many cases we need to run only a handful of commands. Maybe it'll be a good idea in the future. Now you can use redis-cpp like lightweight library to execute Redis commands and get results with minimal effort.

Enjoy your own projects with Redis!

redis-cpp's People

Contributors

bencsikandrei avatar pvenus avatar schoppenglas avatar tdv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redis-cpp's Issues

More connection parameters

Hi!

I've seen that the connection function does not have password into it

i.e.:

auto stream = rediscpp::make_stream("localhost", "6379");

Is there any way to define the password of the connection?

multiple definition in header-only library

I'm attempting to use the header only import of the c++11 branch (basically as described in #4 (comment)). I've included the macro definition #define REDISCPP_HEADER_ONLY, but when I compile it I get the following error:

multiple definition of `rediscpp::resp::deserialization::get_mark(std::istream&)';

I even tried using #ifndef but the issue persisted. I'm not sure what causes this but, if I change:

char get_mark(std::istream &stream)

to:

[[nodiscard]]
inline char get_mark(std::istream &stream)
{

It resolves the issue. I'm not sure if this is the correct way to fix this though. Can anyone confirm this issue / resolution?

CLIENT REPLY

Thanks for sharing your library.

I am assuming the set command is blocking until it receives a response from the server
To improve performance I would like to remove client reply but this command does not work

auto response = rediscpp::execute(*stream, "CLIENT REPLY", "OFF");

any suggestions how I can achieve this ?

Undefined Reference to rediscpp::make_stream

I compiled redis-cpp with following code
`

  1. cd /opt &&\
  2. git clone https://github.com/tdv/redis-cpp.git &&\
  3. cd redis-cpp &&\
  4. mkdir build &&\
  5. cd build &&\
  6. cmake -DREDISCPP_HEADER_ONLY=OFF -DREDISCPP_PURE_CORE=ON .. &&\
  7. make &&\
  8. make install`

On this line

auto redis_client = rediscpp::make_stream(this->redis_host, this->redis_port);

I getting below error

undefined reference to rediscpp::make_stream(std::basic_string_view<char, std::char_traits >, std::basic_string_view<char, std::char_traits >)'
collect2: error: ld returned 1 exit status`

My question is that, How to find redis-cpp in cmake and link with my code??
Any help would be appreciated.

@tdv

elif with no expression

There are elif condition without expression. You can replace elif with else to fix. 👍


/redis-cpp/detail/config.h:19:6: error: #elif with no expression
image

Build errors under Ubuntu 18.04 with GCC 9

When I build under Ubuntu 18.04, I get:

FAILED: src/source.p/source.cpp.o 
c++ -Isrc/source.p -Isrc -I../src -I../include/loguru -Iinclude -I../include -Isrc/test_utils -I../src/test_utils -I../include/test -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -pthread -MD -MQ src/source.p/source.cpp.o -MF src/source.p/source.cpp.o.d -o src/source.p/source.cpp.o -c ../src/source.cpp
In file included from ../include/redis-cpp/stream.h:33,
                 from ../src/source.cpp:37:
../include/redis-cpp/detail/stream.hpp:109:18: error: 'io_context' in namespace 'boost::asio' does not name a type
  109 |     boost::asio::io_context io_context_;
      |                  ^~~~~~~~~~
../include/redis-cpp/detail/stream.hpp:110:42: error: 'io_context_' was not declared in this scope
  110 |     boost::asio::ip::tcp::socket socket_{io_context_};
      |                                          ^~~~~~~~~~~
../include/redis-cpp/detail/stream.hpp:110:53: error: could not convert '{<expression error>}' from '<brace-enclosed initializer list>' to 'boost::asio::ip::tcp::socket' {aka 'boost::asio::basic_stream_socket<boost::asio::ip::tcp>'}
  110 |     boost::asio::ip::tcp::socket socket_{io_context_};
      |                                                     ^
      |                                                     |
      |                                                     <brace-enclosed initializer list>
../include/redis-cpp/detail/stream.hpp: In lambda function:
../include/redis-cpp/detail/stream.hpp:82:57: error: 'io_context_' was not declared in this scope
   82 |                 boost::asio::ip::tcp::resolver resolver{io_context_};
      |                                                         ^~~~~~~~~~~
../include/redis-cpp/detail/stream.hpp:82:68: error: no matching function for call to 'boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(<brace-enclosed initializer list>)'
   82 |                 boost::asio::ip::tcp::resolver resolver{io_context_};
      |                                                                    ^
In file included from /usr/include/boost/asio.hpp:63,
                 from ../include/redis-cpp/detail/stream.hpp:17,
                 from ../include/redis-cpp/stream.h:33,
                 from ../src/source.cpp:37:
/usr/include/boost/asio/ip/basic_resolver.hpp:67:12: note: catestdate: 'boost::asio::ip::basic_resolver<InternetProtocol, ResolverService>::basic_resolver(boost::asio::io_service&) [with InternetProtocol = boost::asio::ip::tcp; ResolverService = boost::asio::ip::resolver_service<boost::asio::ip::tcp>]'
   67 |   explicit basic_resolver(boost::asio::io_service& io_service)
      |            ^~~~~~~~~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:67:12: note:   conversion of argument 1 would be ill-formed:
In file included from ../include/redis-cpp/stream.h:33,
                 from ../src/source.cpp:37:
../include/redis-cpp/detail/stream.hpp:83:83: error: no matching function for call to 'boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::resolve(std::remove_reference<const std::basic_string_view<char>&>::type, std::remove_reference<const std::basic_string_view<char>&>::type)'
   83 |                 auto endpoints = resolver.resolve(std::move(host), std::move(port));
      |                                                                                   ^

This is using the following packages installed:

apt-get update -qq && \
  apt-get install --assume-yes --no-install-recommends \
  ca-certificates \
  build-essential \
  wget \
  ninja-build \
  pkg-config \
  cmake \
  ninja-build \
  libboost-all-dev \
  libcurl4-openssl-dev \
  libpcap-dev \
  libavahi-client-dev \
  python3-pip \
  software-properties-common

add-apt-repository ppa:ubuntu-toolchain-r/test && \
  apt-get update -qq && \
  apt install --assume-yes gcc-9 g++-9 && \
  update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 60 --slave /usr/bin/g++ g++ /usr/bin/g++-9

So I have g++ (Ubuntu 9.4.0-1ubuntu1~18.04) 9.4.0 and libboost-all-dev version 1.65.1.0ubuntu1.

Read array including empty values fails

This is a great library, thank you for sharing this. I think I may have found an issue with rediscpp with MGET where some keys are empty strings (not null). The fix below solves the issue for me.

MGET key1 key2 key3 key4 key5

BEGIN STREAM RETURN
*5
$1109
<1109 chars of key information>
$0

$0

$0

$0

END STREAM RETURN

The fix is in binary_data, to handle items with length 0 as valid data (replace existing code with bold-section):

binary_data(std::istream &stream)
{
    std::string string;
    std::getline(stream, string);
    auto const length = std::stoll(string);
    **if (length < 0)
    {
        is_null_ = true;
        return;
    }**
    data_.resize(static_cast<typename buffer_type::size_type>(length));
    stream.read(&data_[0], length);
    std::getline(stream, string);
}

Avoid installing the library in a hard-coded folder in the root of the cmake project?

Hello! This is more of a question than an issue.

I'm using the library through the CPM "package manager". The static library is installed in a lib folder in the root of my project because of this line:

set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)

Could it make sense to use ${CMAKE_BINARY_DIR} instead of ${CMAKE_SOURCE_DIR}. This gives a library user more control over where the library is installed I think.

Of course adding the lib/ folder to my .gitignore file also solves my problem.

I'm not sure what the cmake best practice is here. Maybe there even is yet an other option that is even better.

Missing cast to array type

Hi I'm not sure if is missing or just not clear, I need to ger from redis, the result of "LARANGE key 0 -1" redis command. But I can not make any cast as_array() or just response.as<std::vevtor std::string >();

How should I parse the result of a LRANGE command ?
Thanks !

Boost ASIO resolver.resolve is deprecated

Hi,

thank you for your great work!
I really like this header only library for redis!

But i get the following compilation error:

In file included from /cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/3rdparty/redis-cpp/include/redis-cpp/stream.h:31,
                 from /cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/mmo-proxy-server.cpp:15:
/cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/3rdparty/redis-cpp/include/redis-cpp/detail/stream.hpp: In constructor 'rediscpp::detail::stream::stream(std::string_view, std::string_view)':
/cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/3rdparty/redis-cpp/include/redis-cpp/detail/stream.hpp:78:53: error: no matching function for call to 'boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::resolve(std::string_view&, std::string_view&)'
   78 |         auto endpoints = resolver.resolve(host, port);
      |                                                     ^
In file included from /usr/include/boost/asio.hpp:80,
                 from /cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/3rdparty/redis-cpp/include/redis-cpp/detail/stream.hpp:15,
                 from /cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/3rdparty/redis-cpp/include/redis-cpp/stream.h:31,
                 from /cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/mmo-proxy-server.cpp:15:
/usr/include/boost/asio/ip/basic_resolver.hpp:214:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const query&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::query = boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp>]'
  214 |   results_type resolve(const query& q)
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:214:16: note:   candidate expects 1 argument, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:235:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const query&, boost::system::error_code&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::query = boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp>]'
  235 |   results_type resolve(const query& q, boost::system::error_code& ec)
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:235:37: note:   no known conversion for argument 1 from 'std::string_view' {aka 'std::basic_string_view<char>'} to 'const query&' {aka 'const boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp>&'}
  235 |   results_type resolve(const query& q, boost::system::error_code& ec)
      |                        ~~~~~~~~~~~~~^
/usr/include/boost/asio/ip/basic_resolver.hpp:274:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  274 |   results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:274:53: note:   no known conversion for argument 1 from 'std::string_view' {aka 'std::basic_string_view<char>'} to 'std::experimental::fundamentals_v1::string_view' {aka 'std::experimental::fundamentals_v1::basic_string_view<char>'}
  274 |   results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host,
      |                                                     ^
/usr/include/boost/asio/ip/basic_resolver.hpp:313:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view, boost::system::error_code&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  313 |   results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:313:16: note:   candidate expects 3 arguments, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:356:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view, boost::asio::ip::resolver_base::flags) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  356 |   results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:356:16: note:   candidate expects 3 arguments, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:405:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view, boost::asio::ip::resolver_base::flags, boost::system::error_code&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  405 |   results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:405:16: note:   candidate expects 4 arguments, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:450:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const protocol_type&, std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::protocol_type = boost::asio::ip::tcp; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  450 |   results_type resolve(const protocol_type& protocol,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:450:16: note:   candidate expects 3 arguments, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:492:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const protocol_type&, std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view, boost::system::error_code&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::protocol_type = boost::asio::ip::tcp; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  492 |   results_type resolve(const protocol_type& protocol,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:492:16: note:   candidate expects 4 arguments, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:539:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const protocol_type&, std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view, boost::asio::ip::resolver_base::flags) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::protocol_type = boost::asio::ip::tcp; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  539 |   results_type resolve(const protocol_type& protocol,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:539:16: note:   candidate expects 4 arguments, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:593:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const protocol_type&, std::experimental::fundamentals_v1::string_view, std::experimental::fundamentals_v1::string_view, boost::asio::ip::resolver_base::flags, boost::system::error_code&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::protocol_type = boost::asio::ip::tcp; std::experimental::fundamentals_v1::string_view = std::experimental::fundamentals_v1::basic_string_view<char>]'
  593 |   results_type resolve(const protocol_type& protocol,
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:593:16: note:   candidate expects 5 arguments, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:932:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const endpoint_type&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::endpoint_type = boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>]'
  932 |   results_type resolve(const endpoint_type& e)
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:932:16: note:   candidate expects 1 argument, 2 provided
/usr/include/boost/asio/ip/basic_resolver.hpp:955:16: note: candidate: 'boost::asio::ip::basic_resolver<InternetProtocol>::results_type boost::asio::ip::basic_resolver<InternetProtocol>::resolve(const endpoint_type&, boost::system::error_code&) [with InternetProtocol = boost::asio::ip::tcp; boost::asio::ip::basic_resolver<InternetProtocol>::results_type = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; boost::asio::ip::basic_resolver<InternetProtocol>::endpoint_type = boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>]'
  955 |   results_type resolve(const endpoint_type& e, boost::system::error_code& ec)
      |                ^~~~~~~
/usr/include/boost/asio/ip/basic_resolver.hpp:955:45: note:   no known conversion for argument 1 from 'std::string_view' {aka 'std::basic_string_view<char>'} to 'const endpoint_type&' {aka 'const boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>&'}
  955 |   results_type resolve(const endpoint_type& e, boost::system::error_code& ec)
      |                        ~~~~~~~~~~~~~~~~~~~~~^
make[3]: *** [CMakeFiles/ProxyServer.dir/build.make:63: CMakeFiles/ProxyServer.dir/mmo-proxy-server.cpp.o] Error 1
make[3]: Leaving directory '/cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/cmake-build-debug'
make[2]: *** [CMakeFiles/Makefile2:76: CMakeFiles/ProxyServer.dir/all] Error 2
make[2]: Leaving directory '/cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/cmake-build-debug'
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/ProxyServer.dir/rule] Error 2
make[1]: Leaving directory '/cygdrive/c/Users/Justin/IdeaProjects/MMOPrototyp/mmo-proxy-server/cmake-build-debug'
make: *** [Makefile:118: ProxyServer] Error 2

As screenshot:
grafik

The problem is, that the resolve function is already deprecated.
grafik

See also: https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/ip__tcp/resolver.html

Can you please fix this?

Could NOT find Boost (missing: thread system iostreams) (found suitable version "1.74.0", minimum required is "1.67.0")

Hi there,

Trying to build con Windows 10 64 bits with Boost 1.74.0 I get this error from Cmake.

Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19042.
The C compiler identification is MSVC 19.16.27044.0
The CXX compiler identification is MSVC 19.16.27044.0
Detecting C compiler ABI info
Detecting C compiler ABI info - done
Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe - skipped
Detecting C compile features
Detecting C compile features - done
Detecting CXX compiler ABI info
Detecting CXX compiler ABI info - done
Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe - skipped
Detecting CXX compile features
Detecting CXX compile features - done
Looking for pthread.h
Looking for pthread.h - not found
Found Threads: TRUE  
CMake Error at C:/Program Files/CMake/share/cmake-3.21/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find Boost (missing: thread system iostreams) (found suitable
  version "1.74.0", minimum required is "1.67.0")
Call Stack (most recent call first):
  C:/Program Files/CMake/share/cmake-3.21/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
  C:/Program Files/CMake/share/cmake-3.21/Modules/FindBoost.cmake:2345 (find_package_handle_standard_args)
  CMakeLists.txt:40 (find_package)


Configuring incomplete, errors occurred!
See also "C:/Users/USER/Downloads/cpp-redis-header/redis-cpp/buildclean/CMakeFiles/CMakeOutput.log".
See also "C:/Users/USER/Downloads/cpp-redis-header/redis-cpp/buildclean/CMakeFiles/CMakeError.log".

I have also try to manually set the path with:

set(BOOST_ROOT "C:/local/boost_1_74_0")
set(Boost_INCLUDE_DIR "C:/local/boost_1_74_0")
set(Boost_LIBRARY_DIR "C:/local/boost_1_74_0/libs")

But still same error.

Also tried with set(Boost_USE_STATIC_LIBS ON) and same error persist.

No luck, hope someone can give me a lead.

'Scan' function type response std::bad_cast issue

Hello, I have no idea how to work with 'scan' functions. For example, when I'm trying to run the following code

auto response = rediscpp::execute(*stream, "scard", "some_set");
std::cout << response.as_integer() << std::endl;
// Output is '4'
response = rediscpp::execute(*stream, "sscan", "some_set", "0");
std::cout << std::boolalpha << response.is_array() << std::endl;
// Output is 'true'
auto vec = response.as_string_array();
// 'bad_cast' error

the last line causes std::bad_cast error, though response.is_array() is true. Furthermore, any available rediscpp cast causes std::bad_cast error. Am i doing something wrong? Is there any way to avoid this error?

how to get pattern/channel info in pub/sub.

Hi, I am using redis-python for publishing the data which is publishing the data in raw format such as -
{'type': 'pmessage',
'pattern': 'channel-*',
'channel': 'channel',
'data': 'data'}.

When i receive it with redis-cpp subscribe, i get all the information but only values (not keys) also as separate/discrete messages like-
pmessage
channel-*
channel
data

if i underline the specific code segmant -
[&print_message] (rediscpp::resp::deserialization::array const &arr)
{
for (auto const &i : arr.get()){
print_message(i);
}

Here i can see the whole array is processed line-by-line and string data is extracted for each line....

My question is can i get the whole array as in json/string format so that i can use that in my way?
Thanks.

how to execute rpush

Hi,
How can i use the redis utilities in pubsub application here like rpush/get/set etc?

Thanks

GET without erasing information.

I'm running the setget example program setget, however for my application i need to do the GET without erasing the redis information. To delete I must do this by the "DEL" command or clean via "FLUSHDB"

SEG SIGNAL when use reset and AUTH enabled

Hi I have found a possible issue , for example using this project I can do the following :

	auto stream = rediscpp::make_stream("127.0.0.1", "6379");
	rediscpp::value response = rediscpp::execute( (*stream), "select", "1");

        if( response.is_error_message() )
	{
		cout << response.as_error_message() << endl;
	}
	else
	{
		cout << response.as_string() << endl;
	}
	
	stream.reset();
	rediscpp::value response = rediscpp::execute( (*stream), "select", "1");

This process works without problems .

But if I enable redis authentication (CONFIG SET requirepass "mypass" or in redis.conf file) ,
the following code generates a SEG SIGNAL .

auto stream = rediscpp::make_stream("127.0.0.1", "6379");
auto response = rediscpp::execute( (*stream), "AUTH", "mypass");
response = rediscpp::execute( (*stream), "select", "1");

cout << response.as_string() << endl; // Here is OK
stream.reset();
response = rediscpp::execute( (*stream), "AUTH", "mypass"); // <- Here segmentation fault

My solution is to re-create the stream ( stream = rediscpp::make_stream("127.0.0.1", "6379"); )
but I think that could be a BUG and I have preferred to report it to collaborate with this fantastic project.
Best regards,
Roni

Array return issues

Great project, very good implementation thanks for this project.
There is no other way to contact you as this is not an issue with the project but my lack of understanding a portion of the code.

I’m executing commands in MVS 2019 on windows but connecting to redis within an Ubuntu VM.
I am primarily working with the Redis TimeSeries module (TSDB). I have successfully ingested data into TSDB but I am having problems syntactically with the return values. Your set and get examples for redis database within the project summarize Bulk/string replies. However, can you please provide an example of an array type reply for commands such as HMGET? Below I will give an example of the TS.GET command which is for the redis time series module but both HMGET and TS.GET return values are array replies.

I’ve been studying the value.h, execute.h, deserialization.h files and looked at your resp serialization and deserialization examples to get an understanding of the code. I’ve looked at value.h line 83

[[nodiscard]] bool is_array() const noexcept {
return marker_ == resp::detail::marker::array;
}
But there is no corresponding return get_value for an array type?

This is what I have done so far:

#define REDISCPP_HEADER_ONLY
#include <redis-cpp/execute.h>
#include <redis-cpp/stream.h>

int main() {
try {

// Create Redis Connection
auto stream = rediscpp::make_stream("localhost", "6379");

// Variables to Create & Add Sample to Redis TimeSeries DB (TSDB)
auto const pmc       = "TS.ADD";    // Redis cmd to create and add TSDB
auto const key       = "MyData";    // Key
auto const times     = "*";         // Redis Arg for auto generated time stamp
auto const sampv     = "1";         // Redis Arg to assign sample number
auto const cmd2      = "RETENTION"; // Redis Arg to assign Retention period of sample
auto const retperiod = "0";         // Retention period set to 0 (Meaning, sample will persist indefinately within TSDB)
auto const cmd3      = "LABELS";    // Redis Arg to assign Labels within TSDB
auto const label1    = "Speed";     // Label 1 = Speed
auto const value1    = "60 mph";    // Value assigned to Label 1
auto const label2    = "Time";
auto const value2    = "2 seconds";

// Execute Command to Create & Add Sample to Redis TimeSeries DB (TSDB)
auto response = rediscpp::execute(*stream, pmc, key, times, sampv, cmd2, retperiod, 
                                   cmd3, label1, value1, label2, value2);

//  No problems here.  Command executes successfully and we have now added a
//  sample to TSDB. If you have Redis TSDB installed TS.INFO MyData should
//  show the following:

/*  1) totalSamples
    2) (integer) 1
    3) memoryUsage
    4) (integer) 4244
    5) firstTimestamp
    6) (integer) 1592739199434
    7) lastTimestamp
    8) (integer) 1592739199434
    9) retentionTime
    10) (integer) 0
    11) chunkCount
    12) (integer) 1
    13) maxSamplesPerChunk
    14) (integer) 256
    15) labels
    16) 1)  1) "Speed"
            2) "60 mph"
        2)  1) "Time"
            2) "2 seconds"
    17) sourceKey
    18) (nil)
    19) rules
    20) (empty list or set)*/

// Problem starts here when we want the return value in the form of an array
// within the client. Redis documentation for TS.GET command - The returned
// array will contain: - The last sample timestamp followed by the last
// sample value, when the time-series contains data. - An empty array, when
// the time-series is empty.

// TS.GET command Variable
auto const redisoutput = "TS.GET";

response = rediscpp::execute(*stream, redisoutput, key);
std::cout << "TS.GET '" << key << "': " << 
response.as<std::string>() << std::endl; //  ---> TS.GET 'MyData': Error: bad cast  

} catch (std::exception const &e) {
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

Any command that returns an array will have the error above : "Error: bad cast". Can you provide an example of an array return with a command like HMGET or TS.GET (if you use TSDB)?

Thanks.

make error

when I make the project , I got this error,please tell me what should I do next, thx a lo
error
t

bad cast while execute "hset"

while execute hset , the type cast will fail and throw exception "bad cast" while cast to string, because the value type of response is integer, I should use as_integer() to cast properly.
But I was developing an app that accept the input from user, so the response from redis will be various, so I need to judge the type of type, it's so inconvenient.
Why not add a method to automatically judge the type and convert it, instead of letting the programmer to judge.

Null Bulk String are converted to empty strings

If I get a non-existing key with the command

rediscpp::value val = rediscpp::execute(*stream, "get", "non existing key");

The server returns a Null Bulk String, but there is no way to differentiate it from an empty string. The variable is_null_ is set to true, but empty() returns false.

Thanks

cannot pass object of non-trivial type 'const rediscpp::resp::deserialization::error_message' through variadic function

I have a simple example:

#include <iostream>

#define REDISCPP_HEADER_ONLY
#include <redis-cpp/stream.h>
#include <redis-cpp/execute.h>

int main(int argc, char *argv[])
{
  try
  {
    auto stream = rediscpp::make_stream(
        "localhost",
        "6379"
      );

    auto const key = "my_key";

    auto response = rediscpp::execute(*stream, "set",
                                      key, "Some value for 'my_key'", "ex", "60");

    std::cout << "Set key '" << key << "': " << response.as<std::string>() << std::endl;

    response = rediscpp::execute(*stream, "get", key);
    std::cout << "Get key '" << key << "': " << response.as<std::string>() << std::endl;

    response = rediscpp::execute(*stream, "del", key);
    std::cout << "Deleted key '" << key << "': " << response.as<std::string>() << std::endl;
  }
  catch (std::exception const &e)
  {
    std::cerr << "Error: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

When compiling this under macOS 10.15.7, I get:

➜ meson compile -C builddir
ninja: Entering directory `builddir'
[1/2] Compiling C++ object redis_test.p/src_redis_test.cpp.o
FAILED: redis_test.p/src_redis_test.cpp.o 
c++ -Iredis_test.p -I. -I.. -I../include/redis-cpp -I../include -Xclang -fcolor-diagnostics -pipe -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -MD -MQ redis_test.p/src_redis_test.cpp.o -MF redis_test.p/src_redis_test.cpp.o.d -o redis_test.p/src_redis_test.cpp.o -c ../src/redis_test.cpp
In file included from ../src/redis_test.cpp:5:
In file included from ../include/redis-cpp/execute.h:21:
../include/redis-cpp/value.h:203:33: error: cannot pass object of non-trivial type 'const rediscpp::resp::deserialization::error_message' through variadic function; call will abort at runtime [-Wnon-pod-varargs]
                    if (is_null(val))
                                ^
../include/redis-cpp/value.h:116:16: note: in instantiation of function template specialization 'rediscpp::value::get_value<std::__1::basic_string_view<char, std::__1::char_traits<char> >, rediscpp::resp::deserialization::error_message>' requested here
        return get_value<std::string_view, resp::deserialization::error_message>();
               ^
../include/redis-cpp/value.h:203:33: error: cannot pass object of non-trivial type 'const rediscpp::resp::deserialization::simple_string' through variadic function; call will abort at runtime [-Wnon-pod-varargs]
                    if (is_null(val))
                                ^
../include/redis-cpp/value.h:122:16: note: in instantiation of function template specialization 'rediscpp::value::get_value<std::__1::basic_string_view<char, std::__1::char_traits<char> >, rediscpp::resp::deserialization::simple_string>' requested here
        return get_value<std::string_view, resp::deserialization::simple_string>();
               ^
2 errors generated.
ninja: build stopped: subcommand failed.

More info on the compiler:

➜ c++ --version
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

Any idea what the problem could be?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.