]> git.mxchange.org Git - hub.git/blob - application/hub/main/dht/class_BaseDht.php
6ad3beda35309fb8c317a99e83ddf1aeb6e6c54e
[hub.git] / application / hub / main / dht / class_BaseDht.php
1 <?php
2 /**
3  * A general DHT class
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 abstract class BaseDht extends BaseHubSystem {
25         /**
26          * "Cached" instance of a publish helper
27          */
28         private $publishHelperInstance = NULL;
29
30         /**
31          * Stacker name for "INSERT" node data
32          */
33         const STACKER_NAME_INSERT_NODE        = 'dht_insert_node';
34         const STACKER_NAME_PENDING_PUBLISHING = 'dht_pending_publish';
35
36         /**
37          * Protected constructor
38          *
39          * @param       $className      Name of the class
40          * @return      void
41          */
42         protected function __construct ($className) {
43                 // Call parent constructor
44                 parent::__construct($className);
45
46                 // Get a stacker instance for this DHT
47                 $stackerInstance = ObjectFactory::createObjectByConfiguredName('dht_stacker_class');
48
49                 // Set it in this class
50                 $this->setStackerInstance($stackerInstance);
51
52                 // Init all stackers
53                 $this->initStacks();
54
55                 /*
56                  * Get the state factory and create the initial state, we don't need
57                  * the state instance here
58                  */
59                 DhtStateFactory::createDhtStateInstanceByName('init', $this);
60         }
61
62         /**
63          * Initializes all stackers
64          *
65          * @return      void
66          */
67         private function initStacks () {
68                 // Initialize all stacker
69                 $this->getStackerInstance()->initStacks(array(
70                         self::STACKER_NAME_INSERT_NODE,
71                         self::STACKER_NAME_PENDING_PUBLISHING,
72                 ));
73         }
74
75         /**
76          * Registers/updates an entry in the DHT with given data from $dhtData
77          * array. Different DHT implemtations may handle this differently as they
78          * may enrich the data with more meta data.
79          *
80          * @param       $dhtData        A valid array with DHT-related data (e.g. node/peer data)
81          * @return      void
82          */
83         protected abstract function insertDataIntoDht (array $dhtData);
84
85         /**
86          * Updates/refreshes DHT data (e.g. status).
87          *
88          * @return      void
89          * @todo        Find more to do here
90          */
91         public function updateDhtData () {
92                 // Set some dummy configuration entries, e.g. dht_status
93                 $this->getConfigInstance()->setConfigEntry('dht_status', $this->getStateInstance()->getStateName());
94         }
95
96         /**
97          * Checks whether there are entries in "INSERT" node data stack
98          *
99          * @return      $isPending      Whether there are pending entries
100          */
101         public function ifInsertNodeDataPending () {
102                 // Determine it if it is not empty
103                 $isPending = ($this->getStackerInstance()->isStackEmpty(self::STACKER_NAME_INSERT_NODE) === FALSE);
104
105                 // Return status
106                 return $isPending;
107         }
108
109         /**
110          * Inserts a single entry of node data into the DHT
111          *
112          * @return      void
113          */
114         public function insertSingleNodeData () {
115                 // Get next node data from stack
116                 $nodeData = $this->getStackerInstance()->popNamed(self::STACKER_NAME_INSERT_NODE);
117
118                 // Make sure $nodeData is really an array and has at least one entry
119                 assert((is_array($nodeData)) && (count($nodeData) > 0));
120
121                 // Insert the data
122                 $this->insertDataIntoDht($nodeData);
123         }
124
125         /**
126          * Checks whether there are unpublished entries
127          *
128          * @return      $hasUnpublished         Whether there are unpublished entries
129          * @todo        Add minimum/maximum age limitations
130          */
131         public function hasUnpublishedEntries () {
132                 // Call method on database wrapper
133                 $hasUnpublished = $this->getWrapperInstance()->hasUnpublishedEntries();
134
135                 // Return it
136                 return $hasUnpublished;
137         }
138
139         /**
140          * Initializes publication of DHT entries. This does only prepare
141          * publication. The next step is to pickup such prepared entries and publish
142          * them by uploading to other (recently appeared) DHT members.
143          *
144          * @return      void
145          */
146         public function initEntryPublication () {
147                 // Call method on database wrapper
148                 $this->getWrapperInstance()->initEntryPublication();
149
150                 // Get result instance
151                 $resultInstance = $this->getWrapperInstance()->getUnpublishedEntriesInstance();
152
153                 // Must still be valid
154                 assert($resultInstance->valid());
155
156                 // "Walk" through all entries
157                 while ($resultInstance->next()) {
158                         // Get current entry
159                         $current = $resultInstance->current();
160
161                         // Make sure only valid entries pass
162                         // @TODO Maybe add more small checks?
163                         assert(is_array($current));
164
165                         // ... and push it to the next stack
166                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('BASE-DHT[' . __METHOD__ . ':' . __LINE__ . '] Pushing entry with ' . count($current) . ' elements to stack ' . self::STACKER_NAME_PENDING_PUBLISHING . ' ...');
167                         $this->getStackerInstance()->pushNamed(self::STACKER_NAME_PENDING_PUBLISHING, $current);
168                 } // END - while
169         }
170
171         /**
172          * Checks whether there are entries pending publication
173          *
174          * @return      $isPending      Whether there are entries pending publication
175          */
176         public function hasEntriesPendingPublication () {
177                 // Determine it if it is not empty
178                 $isPending = ($this->getStackerInstance()->isStackEmpty(self::STACKER_NAME_PENDING_PUBLISHING) === FALSE);
179
180                 // Return status
181                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('BASE-DHT[' . __METHOD__ . ':' . __LINE__ . '] isPending=' . intval($isPending));
182                 return $isPending;
183         }
184
185         /**
186          * Publishes next entry found in stack. This method shall also update the
187          * corresponding dabase entry.
188          *
189          * @return      void
190          * @todo        Find out if loadDescriptorXml() can be called only once to avoid a lot methods working.
191          */
192         public function publishEntry () {
193                 // This test must not fail
194                 assert($this->hasEntriesPendingPublication());
195
196                 // Is there an instance?
197                 if (!$this->publishHelperInstance instanceof HelpableDht) {
198                         // Get a helper instance
199                         $this->publishHelperInstance = ObjectFactory::createObjectByConfiguredName('dht_publish_entry_helper_class');
200                 } // END - if
201
202                 // Load the announcement descriptor
203                 $this->publishHelperInstance->loadDescriptorXml($this);
204
205                 // "Pop" next entry
206                 $entry = $this->getStackerInstance()->popNamed(self::STACKER_NAME_PENDING_PUBLISHING);
207
208                 // Some sanity-checks
209                 assert(is_array($entry));
210
211                 // Remove any non-public data the database layer desires
212                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT[' . $this->__toString() . ']: Calling this->getWrapperInstance()->removeNonPublicDataFromArray(data) ...');
213                 $entry = $this->getWrapperInstance()->removeNonPublicDataFromArray($entry);
214                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT[' . $this->__toString() . ']: entry[]=' . gettype($entry));
215
216                 // Some sanity-checks again
217                 assert(is_array($entry));
218
219                 // Inject variables
220                 $this->publishHelperInstance->getTemplateInstance()->injectConfigVariables($entry);
221
222                 // "Publish" the descriptor by sending it to the bootstrap/list nodes
223                 $this->publishHelperInstance->sendPackage($this);
224         }
225
226         /**
227          * Whether the DHT has fully bootstrapped (after state 'booting')
228          *
229          * @return      $isFullyBooted  Whether the DHT is fully booted
230          * @todo        0% done
231          */
232         public function hasFullyBootstrapped () {
233                 // Get state and check it
234         }
235 }
236
237 // [EOF]
238 ?>