]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/FeedSub/feedinfo.php
some formatting changes to make inblobs work
[quix0rs-gnu-social.git] / plugins / FeedSub / feedinfo.php
1 <?php
2
3 /*
4
5 Subscription flow:
6
7     $feedinfo->subscribe()
8         generate random verification token
9             save to verify_token
10         sends a sub request to the hub...
11     
12     feedsub/callback
13         hub sends confirmation back to us via GET
14         We verify the request, then echo back the challenge.
15         On our end, we save the time we subscribed and the lease expiration
16     
17     feedsub/callback
18         hub sends us updates via POST
19         ?
20     
21 */
22
23 class FeedDBException extends FeedSubException
24 {
25     public $obj;
26
27     function __construct($obj)
28     {
29         parent::__construct('Database insert failure');
30         $this->obj = $obj;
31     }
32 }
33
34 class Feedinfo extends Plugin_DataObject
35 {
36     public $__table = 'feedinfo';
37
38     public $id;
39     public $profile_id;
40
41     public $feeduri;
42     public $homeuri;
43     public $huburi;
44
45     // PuSH subscription data
46     public $verify_token;
47     public $sub_start;
48     public $sub_end;
49
50     public $created;
51     public $lastupdate;
52
53
54     public /*static*/ function staticGet($k, $v=null)
55     {
56         return parent::staticGet(__CLASS__, $k, $v);
57     }
58
59     function tableDef()
60     {
61         class_exists('Schema'); // autoload hack
62         // warning: the autoincrement doesn't seem to set.
63         // alter table feedinfo change column id id int(11) not null  auto_increment;
64         return new TableDef($this->__table,
65                             array(new ColumnDef('id', 'integer',
66                                                 null, false, 'PRI', '0', null, true),
67                                   new ColumnDef('profile_id', 'integer',
68                                                 null, false),
69                                   new ColumnDef('feeduri', 'varchar',
70                                                 255, false, 'UNI'),
71                                   new ColumnDef('homeuri', 'varchar',
72                                                 255, false),
73                                   new ColumnDef('huburi', 'varchar',
74                                                 255, false),
75                                   new ColumnDef('verify_token', 'varchar',
76                                                 32, true),
77                                   new ColumnDef('sub_start', 'datetime',
78                                                 null, true),
79                                   new ColumnDef('sub_end', 'datetime',
80                                                 null, true),
81                                   new ColumnDef('created', 'datetime',
82                                                 null, false),
83                                   new ColumnDef('lastupdate', 'datetime',
84                                                 null, false)));
85     }
86
87     public function getProfile()
88     {
89         return Profile::staticGet('id', $this->profile_id);
90     }
91
92     /**
93      * @param FeedMunger $munger
94      * @return Feedinfo
95      */
96     public static function ensureProfile($munger)
97     {
98         $feedinfo = $munger->feedinfo();
99
100         $current = self::staticGet('feeduri', $feedinfo->feeduri);
101         if ($current) {
102             // @fixme we should probably update info as necessary
103             return $current;
104         }
105
106         $feedinfo->query('BEGIN');
107
108         try {
109             $profile = $munger->profile();
110             $result = $profile->insert();
111             if (empty($result)) {
112                 throw new FeedDBException($profile);
113             }
114
115             $feedinfo->profile_id = $profile->id;
116             $result = $feedinfo->insert();
117             if (empty($result)) {
118                 throw new FeedDBException($feedinfo);
119             }
120
121             $feedinfo->query('COMMIT');
122         } catch (FeedDBException $e) {
123             common_log_db_error($e->obj, 'INSERT', __FILE__);
124             $feedinfo->query('ROLLBACK');
125             return false;
126         }
127         return $feedinfo;
128     }
129
130     /**
131      * Send a subscription request to the hub for this feed.
132      * The hub will later send us a confirmation POST to /feedsub/callback.
133      *
134      * @return bool true on success, false on failure
135      */
136     public function subscribe()
137     {
138         // @fixme use the verification token
139         #$token = md5(mt_rand() . ':' . $this->feeduri);
140         #$this->verify_token = $token;
141         #$this->update(); // @fixme
142         
143         try {
144             $callback = common_local_url('feedsubcallback', array('feed' => $this->id));
145             $headers = array('Content-Type: application/x-www-form-urlencoded');
146             $post = array('hub.mode' => 'subscribe',
147                           'hub.callback' => $callback,
148                           'hub.verify' => 'async',
149                           //'hub.verify_token' => $token,
150                           //'hub.lease_seconds' => 0,
151                           'hub.topic' => $this->feeduri);
152             $client = new HTTPClient();
153             $response = $client->post($this->huburi, $headers, $post);
154             if ($response->getStatus() >= 200 && $response->getStatus() < 300) {
155                 common_log(LOG_INFO, __METHOD__ . ': sub req ok');
156                 return true;
157             } else {
158                 common_log(LOG_INFO, __METHOD__ . ': sub req failed');
159                 return false;
160             }
161         } catch (Exception $e) {
162             // wtf!
163             common_log(LOG_ERR, __METHOD__ . ": error \"{$e->getMessage()}\" hitting hub $this->huburi subscribing to $this->feeduri");
164             return false;
165         }
166     }
167
168     /**
169      * Read and post notices for updates from the feed.
170      * Currently assumes that all items in the feed are new,
171      * coming from a PuSH hub.
172      *
173      * @param string $xml source of Atom or RSS feed
174      */
175     public function postUpdates($xml)
176     {
177         common_log(LOG_INFO, __METHOD__ . ": packet for \"$this->feeduri\"! $xml");
178         require_once "XML/Feed/Parser.php";
179         $feed = new XML_Feed_Parser($xml, false, false, true);
180         $munger = new FeedMunger($feed);
181         
182         $hits = 0;
183         foreach ($feed as $index => $entry) {
184             // @fixme this might sort in wrong order if we get multiple updates
185             
186             $notice = $munger->notice($index);
187             $notice->profile_id = $this->profile_id;
188             
189             // Double-check for oldies
190             // @fixme this could explode horribly for multiple feeds on a blog. sigh
191             $dupe = new Notice();
192             $dupe->uri = $notice->uri;
193             $dupe->find();
194             if ($dupe->fetch()) {
195                 common_log(LOG_WARNING, __METHOD__ . ": tried to save dupe notice for entry {$notice->uri} of feed {$this->feeduri}");
196                 continue;
197             }
198             
199             if (Event::handle('StartNoticeSave', array(&$notice))) {
200                 $id = $notice->insert();
201                 Event::handle('EndNoticeSave', array($notice));
202             }
203             $notice->addToInboxes();
204
205             common_log(LOG_INFO, __METHOD__ . ": saved notice {$notice->id} for entry $index of update to \"{$this->feeduri}\"");
206             $hits++;
207         }
208         if ($hits == 0) {
209             common_log(LOG_INFO, __METHOD__ . ": no updates in packet for \"$this->feeduri\"! $xml");
210         }
211     }
212 }