3 * A database wrapper for distributed hash tables
5 * @author Roland Haeder <webmaster@shipsimu.org>
7 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2014 Hub Developer Team
8 * @license GNU GPL 3.0 or any newer version
9 * @link http://www.shipsimu.org
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 class NodeDistributedHashTableDatabaseWrapper extends BaseDatabaseWrapper implements NodeDhtWrapper, Registerable {
26 * "Cached" results for dabase for looking for unpublished entries
28 private $unpublishedEntriesInstance = NULL;
30 // Constants for database table names
31 const DB_TABLE_NODE_DHT = 'node_dht';
33 // Constants for database column names
34 const DB_COLUMN_NODE_ID = 'node_id';
35 const DB_COLUMN_SESSION_ID = 'session_id';
36 const DB_COLUMN_EXTERNAL_IP = 'external_ip';
37 const DB_COLUMN_LISTEN_PORT = 'listen_port';
38 const DB_COLUMN_PRIVATE_KEY_HASH = 'private_key_hash';
39 const DB_COLUMN_NODE_MODE = 'node_mode';
40 const DB_COLUMN_ACCEPTED_OBJECTS = 'accepted_object_types';
41 const DB_COLUMN_NODE_LIST = 'node_list';
42 const DB_COLUMN_PUBLICATION_STATUS = 'publication_status';
43 const DB_COLUMN_ANSWER_STATUS = 'answer_status';
44 const DB_COLUMN_ACCEPT_BOOTSTRAP = 'accept_bootstrap';
46 // Publication status'
47 const PUBLICATION_STATUS_PENDING = 'PENDING';
50 const EXCEPTION_NODE_ALREADY_REGISTERED = 0x800;
51 const EXCEPTION_NODE_NOT_REGISTERED = 0x801;
54 * Protected constructor
58 protected function __construct () {
59 // Call parent constructor
60 parent::__construct(__CLASS__);
64 * Creates an instance of this database wrapper by a provided user class
66 * @return $wrapperInstance An instance of the created wrapper class
68 public static final function createNodeDistributedHashTableDatabaseWrapper () {
70 $wrapperInstance = new NodeDistributedHashTableDatabaseWrapper();
72 // Set (primary!) table name
73 $wrapperInstance->setTableName(self::DB_TABLE_NODE_DHT);
75 // Return the instance
76 return $wrapperInstance;
80 * Static getter for an array of all DHT database entries
82 * @return $elements All elements for the DHT dabase
84 public static final function getAllElements () {
85 // Create array and ...
87 self::DB_COLUMN_NODE_ID,
88 self::DB_COLUMN_SESSION_ID,
89 self::DB_COLUMN_EXTERNAL_IP,
90 self::DB_COLUMN_LISTEN_PORT,
91 self::DB_COLUMN_PRIVATE_KEY_HASH,
92 self::DB_COLUMN_NODE_MODE,
93 self::DB_COLUMN_ACCEPTED_OBJECTS,
94 self::DB_COLUMN_NODE_LIST
102 * Prepares a search instance for given node data
104 * @param $nodeData An array with valid node data
105 * @return $searchInstance An instance of a SearchCriteria class
107 private function prepareSearchInstance (array $nodeData) {
108 // Assert on array elements
109 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
112 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
114 // Search for node id and limit it to one entry
115 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeData[self::DB_COLUMN_NODE_ID]);
116 $searchInstance->setLimit(1);
119 return $searchInstance;
123 * Getter for result instance for unpublished entries
125 * @return $unpublishedEntriesInstance Result instance
127 public final function getUnpublishedEntriesInstance () {
128 return $this->unpublishedEntriesInstance;
132 * Prepares a "local" instance of a StoreableCriteria class with all node
133 * data for insert/update queries. This data set contains data from *this*
136 * @return $dataSetInstance An instance of a StoreableCriteria class
138 private function prepareLocalDataSetInstance () {
139 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
141 // Get node/request instances
142 $nodeInstance = NodeObjectFactory::createNodeInstance();
143 $requestInstance = ApplicationHelper::getSelfInstance()->getRequestInstance();
145 // Get a dataset instance
146 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
148 // Set the primary key
149 $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID);
151 // Get Universal Node Locator and "explode" it
152 $unl = $nodeInstance->getUniversalNodeLocatorArray();
154 // Make sure both is valid
155 assert(($unl[0] !== 'invalid') && ($unl[1] !== 'invalid') && ($unl[2] !== 'invalid'));
157 // Get an array of all accepted object types
158 $objectList = $nodeInstance->getListFromAcceptedObjectTypes();
160 // Make sure this is an array
161 assert(is_array($objectList));
163 // Add public node data
164 $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_MODE , $requestInstance->getRequestElement('mode'));
165 $dataSetInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP , $unl[0]);
166 $dataSetInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT , $unl[1]);
167 $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId());
168 $dataSetInstance->addCriteria(self::DB_COLUMN_SESSION_ID , $nodeInstance->getSessionId());
169 $dataSetInstance->addCriteria(self::DB_COLUMN_PRIVATE_KEY_HASH, $nodeInstance->getPrivateKeyHash());
170 $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPTED_OBJECTS, implode(BaseHubNode::OBJECT_LIST_SEPARATOR, $objectList));
171 $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPT_BOOTSTRAP, $this->translateBooleanToYesNo($nodeInstance->isAcceptingDhtBootstrap()));
174 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
175 return $dataSetInstance;
179 * Checks whether the local (*this*) node is registered in the DHT by
180 * checking if the external ip/port is found.
182 * @return $isRegistered Whether *this* node is registered in the DHT
184 public function isLocalNodeRegistered () {
185 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
187 // Get a search criteria instance
188 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
191 $nodeInstance = NodeObjectFactory::createNodeInstance();
193 // Get Universal Node Locator and "explode" it
194 $unl = $nodeInstance->getUniversalNodeLocatorArray();
197 * Make sure both is not 'invalid' which means that the resolver
200 assert(($unl[0] !== 'invalid') && ($unl[1] !== 'invalid') && ($unl[2] !== 'invalid'));
202 // Add Universal Node Locator/node id as criteria
203 $searchInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP, $unl[0]);
204 $searchInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT, $unl[1]);
205 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId());
206 $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID , $nodeInstance->getSessionId());
207 $searchInstance->setLimit(1);
209 // Query database and get a result instance back
210 $resultInstance = $this->doSelectByCriteria($searchInstance);
212 // Cache result of if there is an entry, valid() will tell us if an entry is there
213 $isRegistered = $resultInstance->valid();
215 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: isRegistered=' . intval($isRegistered) . ' - EXIT!');
218 return $isRegistered;
222 * Registeres the local (*this*) node with its data in the DHT.
226 public function registerLocalNode () {
227 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
229 // Assert to make sure this method is called with no record in DB (the actual backend of the DHT)
230 assert(!$this->isLocalNodeRegistered());
232 // Get prepared data set instance
233 $dataSetInstance = $this->prepareLocalDataSetInstance();
235 // "Insert" this dataset instance completely into the database
236 $this->queryInsertDataSet($dataSetInstance);
238 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
242 * Updates local (*this*) node's data in DHT, this is but not limited to the
243 * session id, ip number (and/or hostname) and port number.
247 public function updateLocalNode () {
248 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
250 // Assert to make sure this method is called with one record in DB (the actual backend of the DHT)
251 assert($this->isLocalNodeRegistered());
254 $nodeInstance = NodeObjectFactory::createNodeInstance();
256 // Get search criteria
257 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
259 // Search for node id and limit it to one entry
260 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeInstance->getNodeId());
261 $searchInstance->setLimit(1);
263 // Get a prepared dataset instance
264 $dataSetInstance = $this->prepareLocalDataSetInstance();
266 // Set search instance
267 $dataSetInstance->setSearchInstance($searchInstance);
269 // Update DHT database record
270 $this->queryUpdateDataSet($dataSetInstance);
272 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
276 * Finds a node locally by given session id
278 * @param $sessionId Session id to lookup
279 * @return $nodeData Node data array
281 public function findNodeLocalBySessionId ($sessionId) {
282 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: sessionId=' . $sessionId . ' - CALLED!');
284 // Get search criteria
285 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
287 // Search for session id and limit it to one entry
288 $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID, $sessionId);
289 $searchInstance->setLimit(1);
291 // Query database and get a result instance back
292 $resultInstance = $this->doSelectByCriteria($searchInstance);
294 // Return result instance
295 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: resultInstance->valid()=' . intval($resultInstance->valid()) . ' - EXIT!');
296 return $resultInstance;
300 * Registeres a node by given message data.
302 * @param $messageData An array of all message data
303 * @param $handlerInstance An instance of a HandleableDataSet class
306 public function registerNodeByMessageData (array $messageData, HandleableDataSet $handlerInstance) {
307 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: handlerInstance=' . $handlerInstance->__toString() . ' - CALLED!');
309 // Get a data set instance
310 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
312 // Set primary key (session id)
313 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
315 // Add all array elements
316 $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
318 // Remove 'node_list'
319 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
321 // Run the "INSERT" query
322 $this->queryInsertDataSet($dataSetInstance);
324 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . '] - EXIT!');
328 * Updates an existing entry in node list
330 * @param $messageData An array of all message data
331 * @param $handlerInstance An instance of a HandleableDataSet class
332 * @param $searchInstance An instance of LocalSearchCriteria class
335 public function updateNodeByMessageData (array $messageData, HandleableDataSet $handlerInstance, LocalSearchCriteria $searchInstance) {
336 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
338 // Get a data set instance
339 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
341 // Add search instance
342 $dataSetInstance->setSearchInstance($searchInstance);
344 // Set primary key (session id)
345 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
347 // Add all array elements
348 $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
350 // Remove 'node_list'
351 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
353 // Run the "UPDATE" query
354 $this->queryUpdateDataSet($dataSetInstance);
356 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
360 * Determines whether the given node data is already inserted in the DHT
362 * @param $nodeData An array with valid node data
363 * @return $isRegistered Whether the given node data is already inserted
365 public function isNodeRegistered (array $nodeData) {
366 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
368 // Assert on array elements
369 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
371 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: node-id=' . $nodeData[self::DB_COLUMN_NODE_ID]);
373 // Get search criteria
374 $searchInstance = $this->prepareSearchInstance($nodeData);
376 // Query database and get a result instance back
377 $resultInstance = $this->doSelectByCriteria(
380 // Only look for these array elements ("keys")
382 self::DB_COLUMN_NODE_ID => TRUE,
383 self::DB_COLUMN_EXTERNAL_IP => TRUE,
384 self::DB_COLUMN_LISTEN_PORT => TRUE,
388 // Check if there is an entry
389 $isRegistered = $resultInstance->valid();
391 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: isRegistered=' . intval($isRegistered) . ' - EXIT!');
393 // Return registration status
394 return $isRegistered;
398 * Registers a node with given data in the DHT. If the node is already
399 * registered this method shall throw an exception.
401 * @param $nodeData An array with valid node data
403 * @throws NodeAlreadyRegisteredException If the node is already registered
405 public function registerNode (array $nodeData) {
406 // Assert on array elements
407 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
409 // Is the node registered?
410 if ($this->isNodeRegistered($nodeData)) {
411 // Throw an exception
412 throw new NodeAlreadyRegisteredException(array($this, $nodeData), self::EXCEPTION_NODE_ALREADY_REGISTERED);
415 // @TODO Unimplemented part
416 $this->partialStub('nodeData=' . print_r($nodeData, TRUE));
420 * Updates a node's entry in the DHT with given data. This will enrich or
421 * just update already exsiting data. If the node is not found this method
422 * shall throw an exception.
424 * @param $nodeData An array with valid node data
426 * @throws NodeDataMissingException If the node's data is missing
428 public function updateNode (array $nodeData) {
429 // Assert on array elements
430 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
433 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: Updating DHT entry for node-id=' . $nodeData[self::DB_COLUMN_NODE_ID] . ' ...');
435 // Is the node registered?
436 if (!$this->isNodeRegistered($nodeData)) {
437 // No, then throw an exception
438 throw new NodeDataMissingException(array($this, $nodeData), self::EXCEPTION_NODE_NOT_REGISTERED);
441 // Get a search instance
442 $searchInstance = $this->prepareSearchInstance($nodeData);
444 // Get a data set instance
445 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
447 // Add search instance
448 $dataSetInstance->setSearchInstance($searchInstance);
450 // Set primary key (session id)
451 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
454 $nodeInstance = NodeObjectFactory::createNodeInstance();
457 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: nodeData=' . print_r($nodeData, TRUE));
459 // Add all array elements
460 $nodeInstance->addArrayToDataSet($dataSetInstance, $nodeData);
462 // Remove 'node_list'
463 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
465 // Run the "UPDATE" query
466 $this->queryUpdateDataSet($dataSetInstance);
470 * Checks whether there are unpublished entries
472 * @return $hasUnpublished Whether there are unpublished entries
473 * @todo Add minimum/maximum age limitations
475 public function hasUnpublishedEntries () {
476 // Get search instance
477 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
479 // Add exclusion key which is the publish status
480 $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_PUBLICATION_STATUS, NodeDistributedHashTableDatabaseWrapper::PUBLICATION_STATUS_PENDING);
482 // Remember search instance
483 $this->setSearchInstance($searchInstance);
486 $this->unpublishedEntriesInstance = $this->doSelectByCriteria($searchInstance);
488 // Check pending entries
489 $hasUnpublished = $this->unpublishedEntriesInstance->valid();
492 return $hasUnpublished;
496 * Initializes publication of DHT entries. This does only prepare
497 * publication. The next step is to pickup such prepared entries and publish
498 * them by uploading to other (recently appeared) DHT members.
501 * @todo Add timestamp to dataset instance
503 public function initEntryPublication () {
505 * Make sure that hasUnpublishedEntries() has been called first by
506 * asserting on the "cached" object instance. This "caching" saves some
507 * needless queries as this method shall be called immediately after
508 * hasUnpublishedEntries() returns TRUE.
510 assert($this->unpublishedEntriesInstance instanceof SearchableResult);
512 // Result is still okay?
513 assert($this->unpublishedEntriesInstance->valid());
515 // Remove 'publication_status'
516 $this->getSearchInstance()->unsetCriteria(self::DB_COLUMN_PUBLICATION_STATUS);
518 // Make sure all entries are marked as pending, first get a dataset instance.
519 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
521 // Add search instance
522 $dataSetInstance->setSearchInstance($this->getSearchInstance());
524 // Set primary key (node id)
525 $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID);
527 // Add criteria (that should be set)
528 $dataSetInstance->addCriteria(self::DB_COLUMN_PUBLICATION_STATUS, self::PUBLICATION_STATUS_PENDING);
530 // Run the "UPDATE" query
531 $this->queryUpdateDataSet($dataSetInstance);
535 * Removes non-public data from given array.
537 * @param $data An array with possible non-public data that needs to be removed.
538 * @return $data A cleaned up array with only public data.
540 public function removeNonPublicDataFromArray(array $data) {
541 // Currently call only inner method
542 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: Calling parent::removeNonPublicDataFromArray(data) ...');
543 $data = parent::removeNonPublicDataFromArray($data);
544 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: data[]=' . gettype($data));
546 // Return cleaned data
551 * Find recipients for given package data and exclude the sender
553 * @param $packageData An array of valid package data
554 * @return $recipients An indexed array with DHT recipients
556 public function getResultFromExcludedSender (array $packageData) {
557 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
559 // Assert on required array field
560 assert(isset($packageData[NetworkPackage::PACKAGE_DATA_SENDER]));
562 // Get max recipients
563 $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients');
565 // First creata a search instance
566 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
568 // Then exclude 'sender' field as the sender is the current (*this*) node
569 $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_SESSION_ID, $packageData[NetworkPackage::PACKAGE_DATA_SENDER]);
571 // Set limit to maximum DHT recipients
572 $searchInstance->setLimit($maxRecipients);
574 // Get a result instance back from DHT database wrapper.
575 $resultInstance = $this->doSelectByCriteria($searchInstance);
577 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
579 // Return result instance
580 return $resultInstance;
584 * Find recopients by given key/value pair. First look for the key and if it
585 * matches, compare the value.
587 * @param $key Key to look for
588 * @param $value Value to compare if key matches
589 * @return $recipients An indexed array with DHT recipients
591 public function getResultFromKeyValue ($key, $value) {
592 // Get max recipients
593 $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients');
595 // First creata a search instance
596 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
598 // Find the key/value pair
599 $searchInstance->addCriteria($key, $value);
601 // Get a result instance back from DHT database wrapper.
602 $resultInstance = $this->doSelectByCriteria($searchInstance);
604 // Return result instance
605 return $resultInstance;
609 * Enable DHT bootstrap request acceptance for local node
613 public function enableAcceptDhtBootstrap () {
615 /* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: Enabling DHT bootstrap requests ...');
617 // Is the node already registered?
618 if ($this->isLocalNodeRegistered()) {
619 // Just update our record
620 $this->updateLocalNode();
623 $this->registerLocalNode();