diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h index 1c05b6ef74b6f7f6a05ab4c7d284b83897385534..f0d553fa395c270a5a3e9a66d2349ab72e9728c4 100644 --- a/include/opendht/dhtrunner.h +++ b/include/opendht/dhtrunner.h @@ -57,7 +57,7 @@ public: DhtRunner(); virtual ~DhtRunner(); - void get(InfoHash hash, Dht::GetCallback vcb, Dht::DoneCallback dcb=nullptr, Value::Filter f = Value::AllFilter()); + void get(InfoHash hash, Dht::GetCallback vcb, Dht::DoneCallback dcb, Value::Filter f={}); void get(InfoHash hash, Dht::GetCallback vcb, Dht::DoneCallbackSimple cb) { get(hash, vcb, Dht::bindDoneCb(cb)); } @@ -128,10 +128,11 @@ public: void cancelListen(InfoHash h, std::shared_future<size_t> token); void put(InfoHash hash, Value&& value, Dht::DoneCallback cb=nullptr); - void put(const std::string& key, Value&& value, Dht::DoneCallback cb=nullptr); + void put(InfoHash hash, const std::shared_ptr<Value>&, Dht::DoneCallback cb=nullptr); void put(InfoHash hash, Value&& value, Dht::DoneCallbackSimple cb) { put(hash, std::forward<Value>(value), Dht::bindDoneCb(cb)); } + void put(const std::string& key, Value&& value, Dht::DoneCallback cb=nullptr); void cancelPut(const InfoHash& h , const Value::Id& id); @@ -169,6 +170,9 @@ public: return dht_->getNodeId(); } + /** + * @deprecated + */ //[[deprecated]] InfoHash getRoutingId() const { return getNodeId(); diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp index e63cbe3df5f58d553ab724e0fbb3be04c626c875..5042e3c11d345443c5469397b6a4e55796c476f3 100644 --- a/src/dhtrunner.cpp +++ b/src/dhtrunner.cpp @@ -309,6 +309,16 @@ DhtRunner::put(InfoHash hash, Value&& value, Dht::DoneCallback cb) cv.notify_all(); } +void +DhtRunner::put(InfoHash hash, const std::shared_ptr<Value>& value, Dht::DoneCallback cb) +{ + std::lock_guard<std::mutex> lck(storage_mtx); + pending_ops.emplace([=](SecureDht& dht) { + dht.put(hash, value, cb); + }); + cv.notify_all(); +} + void DhtRunner::put(const std::string& key, Value&& value, Dht::DoneCallback cb) { diff --git a/tools/python/opendht.pyx b/tools/python/opendht.pyx new file mode 100644 index 0000000000000000000000000000000000000000..fb05f2d1a0030325336827ce23f6cd7bf42c07d6 --- /dev/null +++ b/tools/python/opendht.pyx @@ -0,0 +1,274 @@ +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 +# distutils: include_dirs = ../../include +# distutils: library_dirs = ../../src +# distutils: libraries = opendht gnutls +# cython: language_level=3 +# +# opendht.pyx - Copyright 2015 by Guillaume Roguez <yomgui1 AT gmail DOT com> +# A Python3 wrapper to access to OpenDHT API +# This wrapper is written for Cython 0.22 +# +# This file is part of OpenDHT Python Wrapper. +# +# OpenDHT Python Wrapper is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# OpenDHT Python Wrapper is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenDHT Python Wrapper. If not, see <http://www.gnu.org/licenses/>. +# + + +from libc.stdint cimport * +from libcpp.string cimport string +from libcpp.vector cimport vector +from libcpp.set cimport set as set +from libcpp cimport bool +from libcpp.utility cimport pair + +from cython.parallel import parallel, prange +from cython.operator cimport dereference as deref, preincrement as inc, predecrement as dec +from cpython cimport ref + +ctypedef uint16_t in_port_t +ctypedef unsigned short int sa_family_t; + + +cdef extern from "<memory>" namespace "std" nogil: + cdef cppclass shared_ptr[T]: + shared_ptr() except + + T* get() + T operator*() + void reset(T*); + +cdef extern from "opendht/infohash.h" namespace "dht": + cdef cppclass InfoHash: + InfoHash() except + + InfoHash(string s) except + + string toString() + bool getBit(unsigned bit) + void setBit(unsigned bit, bool b) + @staticmethod + unsigned commonBits(InfoHash a, InfoHash b) + @staticmethod + InfoHash get(string s) + +cdef extern from "opendht/value.h" namespace "dht": + cdef cppclass Value: + Value() except + + Value(vector[uint8_t]) except + + Value(const uint8_t* dat_ptr, size_t dat_len) except + + string toString() const + +cdef extern from "opendht/dht.h" namespace "dht": + cdef cppclass Node: + Node() except + + InfoHash getId() const + ctypedef bool (*GetCallbackRaw)(vector[shared_ptr[Value]]* values, void *user_data) + ctypedef void (*DoneCallbackRaw)(bool bone, vector[shared_ptr[Node]]* nodes, void *user_data) + cdef cppclass Dht: + cppclass GetCallback: + GetCallback(GetCallbackRaw cb, void *user_data) except + + cppclass DoneCallback: + DoneCallback(DoneCallbackRaw, void *user_data) except + + Dht() except + + InfoHash getNodeId() const + +cdef extern from "opendht/crypto.h" namespace "dht::crypto": + ctypedef pair[shared_ptr[PrivateKey], shared_ptr[Certificate]] Identity + cdef Identity generateIdentity(string name, Identity ca, unsigned bits) + + cdef cppclass PrivateKey: + PrivateKey() + PublicKey getPublicKey() const + + cdef cppclass PublicKey: + PublicKey() + InfoHash getId() const + + cdef cppclass Certificate: + Certificate() + InfoHash getId() const + +cdef class _WithID(object): + def __repr__(self): + return "<%s '%s'>" % (self.__class__.__name__, str(self)) + def __str__(self): + return self.getId().decode() + +cdef class PyInfoHash(_WithID): + cdef InfoHash _infohash + def __init__(self, bytes str=b''): + self._infohash = InfoHash(str) + def getBit(self, bit): + return self._infohash.getBit(bit) + def setBit(self, bit, b): + self._infohash.setBit(bit, b) + def getId(self): + return self._infohash.toString() + @staticmethod + def commonBits(PyInfoHash a, PyInfoHash b): + return InfoHash.commonBits(a._infohash, b._infohash) + @staticmethod + def get(str key): + h = PyInfoHash() + h._infohash = InfoHash.get(key.encode()) + return h + +cdef class PyValue(object): + cdef shared_ptr[Value] _value + def __init__(self, bytes val=b''): + self._value.reset(new Value(val, len(val))) + def __str__(self): + return self._value.get().toString().decode() + +cdef class PyNodeSetIter(object): + cdef set[InfoHash]* _nodes + cdef set[InfoHash].iterator _curIter + def __init__(self, PyNodeSet s): + self._nodes = &s._nodes + self._curIter = self._nodes.begin() + def __next__(self): + if self._curIter == self._nodes.end(): + raise StopIteration + h = PyInfoHash() + h._infohash = deref(self._curIter) + inc(self._curIter) + return h + +cdef class PyNodeSet(object): + cdef set[InfoHash] _nodes + def size(self): + return self._nodes.size() + def insert(self, PyInfoHash l): + self._nodes.insert(l._infohash) + def extend(self, li): + for n in li: + self.insert(n) + def first(self): + if self._nodes.empty(): + raise IndexError() + h = PyInfoHash() + h._infohash = deref(self._nodes.begin()) + return h + def last(self): + if self._nodes.empty(): + raise IndexError() + h = PyInfoHash() + h._infohash = deref(dec(self._nodes.end())) + return h + def __str__(self): + s = '' + cdef set[InfoHash].iterator it = self._nodes.begin() + while it != self._nodes.end(): + s += deref(it).toString().decode() + '\n' + inc(it) + return s + def __iter__(self): + return PyNodeSetIter(self) + +cdef class PyPublicKey(_WithID): + cdef PublicKey _key + def getId(self): + return self._key.getId().toString() + + +cdef class PySharedCertificate(_WithID): + cdef shared_ptr[Certificate] _cert + def getId(self): + return self._cert.get().getId().toString() + + +cdef class PyIdentity(object): + cdef Identity _id; + def generate(self, str name = "pydht", PyIdentity ca = PyIdentity(), unsigned bits = 4096): + self._id = generateIdentity(name.encode(), ca._id, bits) + property PublicKey: + def __get__(self): + k = PyPublicKey() + k._key = self._id.first.get().getPublicKey() + return k + property Certificate: + def __get__(self): + c = PySharedCertificate() + c._cert = self._id.second + return c + +cdef extern from "opendht/dhtrunner.h" namespace "dht": + cdef cppclass DhtRunner: + DhtRunner() except + + InfoHash getId() const + InfoHash getNodeId() const + void bootstrap(const char*, const char*) + void run(in_port_t, const Identity, bool) + void join() + bool isRunning() + string getStorageLog() const + string getRoutingTablesLog(sa_family_t af) const + string getSearchesLog(sa_family_t af) const + void get(InfoHash key, Dht.GetCallback get_cb, Dht.DoneCallback done_cb) + void put(InfoHash key, shared_ptr[Value] val, Dht.DoneCallback done_cb) + +cdef bool py_get_callback(vector[shared_ptr[Value]]* values, void *user_data) with gil: + cb = (<object>user_data)['get'] + for v in deref(values): + pv = PyValue() + pv._value = v + if not cb(pv): + return False + return True + +cdef void py_done_callback(bool done, vector[shared_ptr[Node]]* nodes, void *user_data) with gil: + node_ids = [] + for n in deref(nodes): + h = PyInfoHash() + h._infohash = n.get().getId() + node_ids.append(h) + (<object>user_data)['done'](done, node_ids) + ref.Py_DECREF(<object>user_data) + +cdef class PyDhtRunner(_WithID): + cdef DhtRunner* thisptr; + def __cinit__(self): + self.thisptr = new DhtRunner() + def getId(self): + return self.thisptr.getId().toString() + def getNodeId(self): + return self.thisptr.getNodeId().toString() + def bootstrap(self, str host, str port): + self.thisptr.bootstrap(host.encode(), port.encode()) + def run(self, in_port_t port, PyIdentity id, bool threaded=False): + self.thisptr.run(port, id._id, threaded) + def join(self): + self.thisptr.join() + def isRunning(self): + return self.thisptr.isRunning() + def getStorageLog(self): + return self.thisptr.getStorageLog().decode() + def getRoutingTablesLog(self, sa_family_t af): + return self.thisptr.getRoutingTablesLog(af).decode() + def getSearchesLog(self, sa_family_t af): + return self.thisptr.getSearchesLog(af).decode() + def get(self, PyInfoHash key, get_cb, done_cb): + cb_obj = {'get':get_cb, 'done':done_cb} + ref.Py_INCREF(cb_obj) + self.thisptr.get(key._infohash, Dht.GetCallback(py_get_callback, <void*>cb_obj), Dht.DoneCallback(py_done_callback, <void*>cb_obj)) + def get(self, str key, get_cb, done_cb): + cb_obj = {'get':get_cb, 'done':done_cb} + ref.Py_INCREF(cb_obj) + self.thisptr.get(InfoHash.get(key.encode()), Dht.GetCallback(py_get_callback, <void*>cb_obj), Dht.DoneCallback(py_done_callback, <void*>cb_obj)) + def put(self, PyInfoHash key, PyValue val, done_cb): + cb_obj = {'done':done_cb} + ref.Py_INCREF(cb_obj) + self.thisptr.put(key._infohash, val._value, Dht.DoneCallback(py_done_callback, <void*>cb_obj)) + def put(self, str key, PyValue val, done_cb): + cb_obj = {'done':done_cb} + ref.Py_INCREF(cb_obj) + self.thisptr.put(InfoHash.get(key.encode()), val._value, Dht.DoneCallback(py_done_callback, <void*>cb_obj)) diff --git a/tools/python/setup.py b/tools/python/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..d3845fbd71a82ab4229f6bcce9a4a6f243eb00a0 --- /dev/null +++ b/tools/python/setup.py @@ -0,0 +1,37 @@ +# This file is copyright 2015 by Guillaume Roguez <yomgui1 AT gmail DOT com> +# A Python3 wrapper to access to OpenDHT API +# This wrapper is written for Cython 0.22 +# +# This file is part of OpenDHT Python Wrapper. +# +# OpenDHT Python Wrapper is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# OpenDHT Python Wrapper is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenDHT Python Wrapper. If not, see <http://www.gnu.org/licenses/>. +# + +from distutils.core import setup, Extension +from Cython.Build import cythonize + +setup(name="opendht", + version="0.1", + description="Cython generated wrapper for opendht", + author="Guillaume Roguez", + license="GPLv3", + ext_modules = cythonize(Extension( + "opendht", + ["opendht.pyx"], + language="c++", + extra_compile_args=["-std=c++11"], + extra_link_args=["-std=c++11"], + libraries=["opendht"] + )) +)