]> git.mxchange.org Git - hub.git/blob - application/hub/main/database/wrapper/node/class_NodeDistributedHashTableDatabaseWrapper.php
Don't publish private key in DHT (all data will be published).
[hub.git] / application / hub / main / database / wrapper / node / class_NodeDistributedHashTableDatabaseWrapper.php
1 <?php
2 /**
3  * A database wrapper for distributed hash tables
4  *
5  * @author              Roland Haeder <webmaster@shipsimu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 Hub Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.shipsimu.org
10  *
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.
15  *
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.
20  *
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/>.
23  */
24 class NodeDistributedHashTableDatabaseWrapper extends BaseDatabaseWrapper implements NodeDhtWrapper, Registerable {
25         // Constants for database table names
26         const DB_TABLE_NODE_DHT = 'node_dht';
27
28         // Constants for database column names
29         const DB_COLUMN_NODE_ID          = 'node_id';
30         const DB_COLUMN_SESSION_ID       = 'session_id';
31         const DB_COLUMN_EXTERNAL_IP      = 'external_ip';
32         const DB_COLUMN_LISTEN_PORT      = 'listen_port';
33         const DB_COLUMN_PRIVATE_KEY_HASH = 'private_key_hash';
34         const DB_COLUMN_NODE_MODE        = 'node_mode';
35         const DB_COLUMN_ACCEPTED_OBJECTS = 'accepted_object_types';
36         const DB_COLUMN_NODE_LIST        = 'node_list';
37
38         // Exception codes
39         const EXCEPTION_NODE_ALREADY_REGISTERED = 0x800;
40         const EXCEPTION_NODE_NOT_REGISTERED     = 0x801;
41
42         /**
43          * Protected constructor
44          *
45          * @return      void
46          */
47         protected function __construct () {
48                 // Call parent constructor
49                 parent::__construct(__CLASS__);
50         }
51
52         /**
53          * Creates an instance of this database wrapper by a provided user class
54          *
55          * @return      $wrapperInstance        An instance of the created wrapper class
56          */
57         public static final function createNodeDistributedHashTableDatabaseWrapper () {
58                 // Get a new instance
59                 $wrapperInstance = new NodeDistributedHashTableDatabaseWrapper();
60
61                 // Set (primary!) table name
62                 $wrapperInstance->setTableName(self::DB_TABLE_NODE_DHT);
63
64                 // Return the instance
65                 return $wrapperInstance;
66         }
67
68         /**
69          * Prepares a "local" instance of a StoreableCriteria class with all node
70          * data for insert/update queries. This data set contains data from *this*
71          * (local) node.
72          *
73          * @return      $dataSetInstance        An instance of a StoreableCriteria class
74          */
75         private function prepareLocalDataSetInstance () {
76                 // Get node/request instances
77                 $nodeInstance = Registry::getRegistry()->getInstance('node');
78                 $requestInstance = ApplicationHelper::getSelfInstance()->getRequestInstance();
79
80                 // Get a dataset instance
81                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
82
83                 // Set the primary key
84                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID);
85
86                 // Get ip:port combination and "explode" it
87                 $ipPort = $nodeInstance->getAddressPortArray();
88
89                 // Make sure both is valid
90                 assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid'));
91
92                 // Get an array of all accepted object types
93                 $objectList = $nodeInstance->getListFromAcceptedObjectTypes();
94
95                 // Make sure this is an array
96                 assert(is_array($objectList));
97
98                 // Add public node data
99                 $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_MODE       , $requestInstance->getRequestElement('mode'));
100                 $dataSetInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP     , $ipPort[0]);
101                 $dataSetInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT     , $ipPort[1]);
102                 $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_ID         , $nodeInstance->getNodeId());
103                 $dataSetInstance->addCriteria(self::DB_COLUMN_SESSION_ID      , $nodeInstance->getSessionId());
104                 $dataSetInstance->addCriteria(self::DB_COLUMN_PRIVATE_KEY_HASH, $nodeInstance->getPrivateKeyHash());
105                 $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPTED_OBJECTS, implode(BaseHubNode::OBJECT_LIST_SEPARATOR, $objectList));
106
107                 // Return it
108                 return $dataSetInstance;
109         }
110
111         /**
112          * Checks whether the local (*this*) node is registered in the DHT by
113          * checking if the external ip/port is found.
114          *
115          * @return      $isRegistered   Whether *this* node is registered in the DHT
116          */
117         public function isLocalNodeRegistered () {
118                 // Is there cache?
119                 if (!isset($GLOBALS[__METHOD__])) {
120                         // Get a search criteria instance
121                         $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
122
123                         // Get node instance
124                         $nodeInstance = Registry::getRegistry()->getInstance('node');
125
126                         // Get ip:port combination and "explode" it
127                         $ipPort = $nodeInstance->getAddressPortArray();
128
129                         /*
130                          * Make sure both is not 'invalid' which means that the resolver
131                          * didn't work.
132                          */
133                         assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid'));
134
135                         // Add ip:port/node id as criteria
136                         $searchInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP, $ipPort[0]);
137                         $searchInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT, $ipPort[1]);
138                         $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID    , $nodeInstance->getNodeId());
139                         $searchInstance->setLimit(1);
140
141                         // Query database and get a result instance back
142                         $resultInstance = $this->doSelectByCriteria($searchInstance);
143
144                         // Cache result of if there is an entry, valid() will tell us if an entry is there
145                         $GLOBALS[__METHOD__] = $resultInstance->valid();
146                 } // END - if
147
148                 // Return result
149                 return $GLOBALS[__METHOD__];
150         }
151
152         /**
153          * Registeres the local (*this*) node with its data in the DHT.
154          *
155          * @return      void
156          */
157         public function registerLocalNode () {
158                 // Assert to make sure this method is called with no record in DB (the actual backend of the DHT)
159                 assert(!$this->isLocalNodeRegistered());
160
161                 // Get prepared data set instance
162                 $dataSetInstance = $this->prepareLocalDataSetInstance();
163
164                 // "Insert" this dataset instance completely into the database
165                 $this->queryInsertDataSet($dataSetInstance);
166         }
167
168         /**
169          * Updates local (*this*) node data in DHT, this is but not limited to the
170          * session id, ip number (and/or hostname) and port number.
171          *
172          * @return      void
173          */
174         public function updateLocalNode () {
175                 // Assert to make sure this method is called with one record in DB (the actual backend of the DHT)
176                 assert($this->isLocalNodeRegistered());
177
178                 // Get node instance
179                 $nodeInstance = Registry::getRegistry()->getInstance('node');
180
181                 // Get search criteria
182                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
183
184                 // Search for node id and limit it to one entry
185                 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeInstance->getNodeId());
186                 $searchInstance->setLimit(1);
187
188                 // Get a prepared dataset instance
189                 $dataSetInstance = $this->prepareLocalDataSetInstance();
190
191                 // Set search instance
192                 $dataSetInstance->setSearchInstance($searchInstance);
193
194                 // Update DHT database record
195                 $this->queryUpdateDataSet($dataSetInstance);
196         }
197
198         /**
199          * Finds a node locally by given session id
200          *
201          * @param       $sessionId      Session id to lookup
202          * @return      $nodeData       Node data array
203          */
204         public function findNodeLocalBySessionId ($sessionId) {
205                 // Get search criteria
206                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
207
208                 // Search for session id and limit it to one entry
209                 $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID, $sessionId);
210                 $searchInstance->setLimit(1);
211
212                 // Query database and get a result instance back
213                 $resultInstance = $this->doSelectByCriteria($searchInstance);
214
215                 // Return result instance
216                 return $resultInstance;
217         }
218
219         /**
220          * Registeres a node by given message data.
221          *
222          * @param       $messageData            An array of all message data
223          * @param       $handlerInstance        An instance of a HandleableMessage class
224          * @return      void
225          */
226         public function registerNodeByMessageData (array $messageData, Handleable $handlerInstance) {
227                 // Get a data set instance
228                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
229
230                 // Set primary key (session id)
231                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
232
233                 // Add all array elements
234                 $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
235
236                 // Remove 'node_list'
237                 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
238
239                 // Run the "INSERT" query
240                 $this->queryInsertDataSet($dataSetInstance);
241         }
242
243         /**
244          * Updates an existing entry in node list
245          *
246          * @param       $messageData            An array of all message data
247          * @param       $handlerInstance        An instance of a HandleableMessage class
248          * @param       $searchInstance         An instance of LocalSearchCriteria class
249          * @return      void
250          */
251         public function updateNodeByMessageData (array $messageData, Handleable $handlerInstance, LocalSearchCriteria $searchInstance) {
252                 // Get a data set instance
253                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
254
255                 // Add search instance
256                 $dataSetInstance->setSearchInstance($searchInstance);
257
258                 // Set primary key (session id)
259                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
260
261                 // Add all array elements
262                 $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
263
264                 // Remove 'node_list'
265                 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
266
267                 // Run the "UPDATE" query
268                 $this->queryUpdateDataSet($dataSetInstance);
269         }
270
271         /**
272          * Determines whether the given node data is already inserted in the DHT
273          *
274          * @param       $nodeData               An array with valid node data
275          * @return      $isRegistered   Whether the given node data is already inserted
276          */
277         public function isNodeRegistered (array $nodeData) {
278                 // Get search criteria
279                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
280
281                 // Search for node id and limit it to one entry
282                 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeData[self::DB_COLUMN_NODE_ID]);
283                 $searchInstance->setLimit(1);
284
285                 // Query database and get a result instance back
286                 $resultInstance = $this->doSelectByCriteria(
287                         // Search instance
288                         $searchInstance,
289                         // Only look for these array elements ("keys")
290                         array(
291                                 self::DB_COLUMN_NODE_ID     => TRUE,
292                                 self::DB_COLUMN_EXTERNAL_IP => TRUE,
293                                 self::DB_COLUMN_LISTEN_PORT => TRUE,
294                         )
295                 );
296
297                 // Check if there is an entry
298                 $isRegistered = $resultInstance->valid();
299
300                 // Return registration status
301                 return $isRegistered;
302         }
303
304         /**
305          * Registers a node with given data in the DHT. If the node is already
306          * registered this method shall throw an exception.
307          *
308          * @param       $nodeData       An array with valid node data
309          * @return      void
310          * @throws      NodeAlreadyRegisteredException  If the node is already registered
311          */
312         public function registerNode (array $nodeData) {
313                 // Is the node registered?
314                 if ($this->isNodeRegistered($nodeData)) {
315                         // Throw an exception
316                         throw new NodeAlreadyRegisteredException(array($this, $nodeData), self::EXCEPTION_NODE_ALREADY_REGISTERED);
317                 } // END - if
318
319                 // @TODO Unimplemented part
320                 $this->partialStub('nodeData=' . print_r($nodeData, TRUE));
321         }
322
323         /**
324          * Updates a node's entry in the DHT with given data. This will enrich or
325          * just update already exsiting data. If the node is not found this method
326          * shall throw an exception.
327          *
328          * @param       $nodeData       An array with valid node data
329          * @return      void
330          * @throws      NodeDataMissingException        If the node's data is missing
331          */
332         public function updateNode (array $nodeData) {
333                 // Is the node registered?
334                 if (!$this->isNodeRegistered($nodeData)) {
335                         // No, then throw an exception
336                         throw new NodeDataMissingException(array($this, $nodeData), self::EXCEPTION_NODE_NOT_REGISTERED);
337                 } // END - if
338
339                 // @TODO Unimplemented part
340                 $this->partialStub('nodeData=' . print_r($nodeData, TRUE));
341         }
342 }
343
344 // [EOF]
345 ?>