const DB_TABLE_NODE_DHT = 'node_dht';
// Constants for database column names
- const DB_COLUMN_NODE_ID = 'node_id';
- const DB_COLUMN_SESSION_ID = 'session_id';
- const DB_COLUMN_IP_PORT = 'ip_port';
+ const DB_COLUMN_NODE_ID = 'node_id';
+ const DB_COLUMN_SESSION_ID = 'session_id';
+ const DB_COLUMN_EXTERNAL_IP = 'external_ip';
+ const DB_COLUMN_LISTEN_PORT = 'listen_port';
+ const DB_COLUMN_PRIVATE_KEY = 'private_key';
+ const DB_COLUMN_PRIVATE_KEY_HASH = 'private_key_hash';
+ const DB_COLUMN_NODE_MODE = 'node_mode';
+ const DB_COLUMN_ACCEPTED_OBJECTS = 'accepted_object_types';
+ const DB_COLUMN_NODE_LIST = 'node_list';
+
+ // Exception codes
+ const EXCEPTION_NODE_ALREADY_REGISTERED = 0x800;
+ const EXCEPTION_NODE_NOT_REGISTERED = 0x801;
/**
* Protected constructor
return $wrapperInstance;
}
+ /**
+ * Prepares a "local" instance of a StoreableCriteria class with all node
+ * data for insert/update queries. This data set contains data from *this*
+ * (local) node.
+ *
+ * @return $dataSetInstance An instance of a StoreableCriteria class
+ */
+ private function prepareLocalDataSetInstance () {
+ // Get node/request instances
+ $nodeInstance = Registry::getRegistry()->getInstance('node');
+ $requestInstance = ApplicationHelper::getSelfInstance()->getRequestInstance();
+
+ // Get a dataset instance
+ $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
+
+ // Set the primary key
+ $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID);
+
+ // Get ip:port combination and "explode" it
+ $ipPort = $nodeInstance->getAddressPortArray();
+
+ // Make sure both is valid
+ assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid'));
+
+ // Get an array of all accepted object types
+ $objectList = $nodeInstance->getListFromAcceptedObjectTypes();
+
+ // Make sure this is an array
+ assert(is_array($objectList));
+
+ // Add public node data
+ $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_MODE , $requestInstance->getRequestElement('mode'));
+ $dataSetInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP , $ipPort[0]);
+ $dataSetInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT , $ipPort[1]);
+ $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId());
+ $dataSetInstance->addCriteria(self::DB_COLUMN_SESSION_ID , $nodeInstance->getSessionId());
+ $dataSetInstance->addCriteria(self::DB_COLUMN_PRIVATE_KEY_HASH, $nodeInstance->getPrivateKeyHash());
+ $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPTED_OBJECTS, implode(BaseHubNode::OBJECT_LIST_SEPARATOR, $objectList));
+
+ // Return it
+ return $dataSetInstance;
+ }
+
/**
* Checks whether the local (*this*) node is registered in the DHT by
* checking if the external ip/port is found.
* @return $isRegistered Whether *this* node is registered in the DHT
*/
public function isLocalNodeRegistered () {
- // Get a search criteria instance
- $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
+ // Is there cache?
+ if (!isset($GLOBALS[__METHOD__])) {
+ // Get a search criteria instance
+ $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
- // Get node instance
- $nodeInstance = Registry::getRegistry()->getInstance('node');
+ // Get node instance
+ $nodeInstance = Registry::getRegistry()->getInstance('node');
- // Add ip:port as criteria
- $searchInstance->addCriteria(self::DB_COLUMN_IP_PORT, $nodeInstance->getAddressPort());
- $searchInstance->setLimit(1);
+ // Get ip:port combination and "explode" it
+ $ipPort = $nodeInstance->getAddressPortArray();
- // Query database and get a result instance back
- $resultInstance = $this->doSelectByCriteria($searchInstance);
+ /*
+ * Make sure both is not 'invalid' which means that the resolver
+ * didn't work.
+ */
+ assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid'));
+
+ // Add ip:port/node id as criteria
+ $searchInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP, $ipPort[0]);
+ $searchInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT, $ipPort[1]);
+ $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId());
+ $searchInstance->setLimit(1);
- // Is there an entry?
- $isRegistered = $resultInstance->next();
+ // Query database and get a result instance back
+ $resultInstance = $this->doSelectByCriteria($searchInstance);
+
+ // Cache result of if there is an entry, valid() will tell us if an entry is there
+ $GLOBALS[__METHOD__] = $resultInstance->valid();
+ } // END - if
// Return result
- return $isRegistered;
+ return $GLOBALS[__METHOD__];
}
/**
* @return void
*/
public function registerLocalNode () {
- $this->partialStub('Not implemented yet.');
+ // Assert to make sure this method is called with no record in DB (the actual backend of the DHT)
+ assert(!$this->isLocalNodeRegistered());
+
+ // Get prepared data set instance
+ $dataSetInstance = $this->prepareLocalDataSetInstance();
+
+ // "Insert" this dataset instance completely into the database
+ $this->queryInsertDataSet($dataSetInstance);
}
/**
* @return void
*/
public function updateLocalNode () {
- $this->partialStub('Not implemented yet.');
+ // Assert to make sure this method is called with one record in DB (the actual backend of the DHT)
+ assert($this->isLocalNodeRegistered());
+
+ // Get node instance
+ $nodeInstance = Registry::getRegistry()->getInstance('node');
+
+ // Get search criteria
+ $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
+
+ // Search for node id and limit it to one entry
+ $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeInstance->getNodeId());
+ $searchInstance->setLimit(1);
+
+ // Get a prepared dataset instance
+ $dataSetInstance = $this->prepareLocalDataSetInstance();
+
+ // Set search instance
+ $dataSetInstance->setSearchInstance($searchInstance);
+
+ // Update DHT database record
+ $this->queryUpdateDataSet($dataSetInstance);
+ }
+
+ /**
+ * Finds a node locally by given session id
+ *
+ * @param $sessionId Session id to lookup
+ * @return $nodeData Node data array
+ */
+ public function findNodeLocalBySessionId ($sessionId) {
+ // Get search criteria
+ $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
+
+ // Search for session id and limit it to one entry
+ $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID, $sessionId);
+ $searchInstance->setLimit(1);
+
+ // Query database and get a result instance back
+ $resultInstance = $this->doSelectByCriteria($searchInstance);
+
+ // Return result instance
+ return $resultInstance;
+ }
+
+ /**
+ * Registeres a node by given message data.
+ *
+ * @param $messageData An array of all message data
+ * @param $handlerInstance An instance of a HandleableMessage class
+ * @return void
+ */
+ public function registerNodeByMessageData (array $messageData, Handleable $handlerInstance) {
+ // Get a data set instance
+ $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
+
+ // Set primary key (session id)
+ $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
+
+ // Add all array elements
+ $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
+
+ // Remove 'node_list'
+ $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
+
+ // Run the "INSERT" query
+ $this->queryInsertDataSet($dataSetInstance);
+ }
+
+ /**
+ * Updates an existing entry in node list
+ *
+ * @param $messageData An array of all message data
+ * @param $handlerInstance An instance of a HandleableMessage class
+ * @param $searchInstance An instance of LocalSearchCriteria class
+ * @return void
+ */
+ public function updateNodeByMessageData (array $messageData, Handleable $handlerInstance, LocalSearchCriteria $searchInstance) {
+ // Get a data set instance
+ $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
+
+ // Add search instance
+ $dataSetInstance->setSearchInstance($searchInstance);
+
+ // Set primary key (session id)
+ $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
+
+ // Add all array elements
+ $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
+
+ // Remove 'node_list'
+ $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
+
+ // Run the "UPDATE" query
+ $this->queryUpdateDataSet($dataSetInstance);
+ }
+
+ /**
+ * Determines whether the given node data is already inserted in the DHT
+ *
+ * @param $nodeData An array with valid node data
+ * @return $isRegistered Whether the given node data is already inserted
+ */
+ public function isNodeRegistered (array $nodeData) {
+ // Get search criteria
+ $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
+
+ // Search for node id and limit it to one entry
+ $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeData[self::DB_COLUMN_NODE_ID]);
+ $searchInstance->setLimit(1);
+
+ // Query database and get a result instance back
+ $resultInstance = $this->doSelectByCriteria($searchInstance);
+
+ // Check if there is an entry
+ $isRegistered = $resultInstance->valid();
+
+ // Return registration status
+ return $isRegistered;
+ }
+
+ /**
+ * Registers a node with given data in the DHT. If the node is already
+ * registered this method shall throw an exception.
+ *
+ * @param $nodeData An array with valid node data
+ * @return void
+ * @throws NodeAlreadyRegisteredException If the node is already registered
+ */
+ public function registerNode (array $nodeData) {
+ // Is the node registered?
+ if ($this->isNodeRegistered($nodeData)) {
+ // Throw an exception
+ throw new NodeAlreadyRegisteredException(array($this, $nodeData), self::EXCEPTION_NODE_ALREADY_REGISTERED);
+ } // END - if
+
+ // @TODO Unimplemented part
+ $this->partialStub('nodeData=' . print_r($nodeData, TRUE));
+ }
+
+ /**
+ * Updates a node's entry in the DHT with given data. This will enrich or
+ * just update already exsiting data. If the node is not found this method
+ * shall throw an exception.
+ *
+ * @param $nodeData An array with valid node data
+ * @return void
+ * @throws NodeDataMissingException If the node's data is missing
+ */
+ public function updateNode (array $nodeData) {
+ // Is the node registered?
+ if (!$this->isNodeRegistered($nodeData)) {
+ // No, then throw an exception
+ throw new NodeDataMissingException(array($this, $nodeData), self::EXCEPTION_NODE_NOT_REGISTERED);
+ } // END - if
+
+ // @TODO Unimplemented part
+ $this->partialStub('nodeData=' . print_r($nodeData, TRUE));
}
}