Browse Source

support unsubscribing

master
Aaron Parecki 9 years ago
parent
commit
1a698cf9ee
3 changed files with 74 additions and 39 deletions
  1. +40
    -24
      controllers/push.php
  2. +23
    -15
      lib/PushTask.php
  3. +11
    -0
      lib/db_helpers.php

+ 40
- 24
controllers/push.php View File

@ -24,8 +24,9 @@ $app->get('/callback-fail', function() use($app) {
$app->post('/', function() use($app) { $app->post('/', function() use($app) {
$params = $app->request()->params(); $params = $app->request()->params();
switch(k($params, 'hub_mode')) {
switch($mode=k($params, 'hub_mode')) {
case 'subscribe': case 'subscribe':
case 'unsubscribe':
// Sanity check the request params // Sanity check the request params
$topic = k($params, 'hub_topic'); $topic = k($params, 'hub_topic');
@ -39,32 +40,48 @@ $app->post('/', function() use($app) {
push_error($app, 'Callback URL was invalid'); push_error($app, 'Callback URL was invalid');
} }
// If we've already seen the topic, assume it's valid and don't check it again
if(!db\feed_from_url($topic)) {
$topic_head = request\get_head($topic);
if($topic_head && !request\response_is($topic_head['status'], 2)) {
push_error($app, "The topic URL returned a " . $topic_head['status'] . " status code");
} else {
push_error($app, 'We tried to verify the topic URL exists but it didn\'t respond to a HEAD request.');
if($mode == 'subscribe') {
// If we've already seen the topic, assume it's valid and don't check it again
if(!db\feed_from_url($topic)) {
$topic_head = request\get_head($topic);
if($topic_head && !request\response_is($topic_head['status'], 2)) {
push_error($app, "The topic URL returned a " . $topic_head['status'] . " status code");
} else {
push_error($app, 'We tried to verify the topic URL exists but it didn\'t respond to a HEAD request.');
}
} }
}
// Find or create the feed given the topic URL
$feed = db\find_or_create('feeds', ['feed_url'=>$topic], [
'hash' => db\random_hash(),
], true);
// Find or create the feed given the topic URL
$feed = db\find_or_create('feeds', ['feed_url'=>$topic], [
'hash' => db\random_hash(),
], true);
// Find or create the subscription for this callback URL and feed
$subscription = db\find_or_create('subscriptions', ['feed_id'=>$feed->id, 'callback_url'=>$callback], [
'hash' => db\random_hash()
], true);
// Always set a new requested date and challenge
$subscription->date_requested = db\now();
$subscription->challenge = db\random_hash();
$subscription->save();
// Queue the worker to validate the subscription
DeferredTask::queue('PushTask', 'verify_subscription', [$subscription->id, 'subscribe']);
} else {
$feed = db\feed_from_url($topic);
if(!$feed) {
push_error($app, 'The topic was not found, so there is no subscription active');
}
// Find or create the subscription for this callback URL and feed
$subscription = db\find_or_create('subscriptions', ['feed_id'=>$feed->id, 'callback_url'=>$callback], [
'hash' => db\random_hash()
], true);
// Always set a new requested date and challenge
$subscription->date_requested = db\now();
$subscription->challenge = db\random_hash();
$subscription->save();
$subscription = db\find('subscriptions', ['feed_id'=>$feed->id, 'callback_url'=>$callback]);
if(!$subscription) {
push_error($app, 'There was no subscription found for this callback URL and topic');
}
// Queue the worker to validate the subscription
DeferredTask::queue('PushTask', 'verify_subscription', $subscription->id);
// Queue the worker to validate the subscription
DeferredTask::queue('PushTask', 'verify_subscription', [$subscription->id, 'unsubscribe']);
}
$app->response()->status(202); $app->response()->status(202);
echo "The subscription request is being validated. Check the status here:\n"; echo "The subscription request is being validated. Check the status here:\n";
@ -72,7 +89,6 @@ $app->post('/', function() use($app) {
break; break;
case 'unsubscribe':
break; break;
} }

+ 23
- 15
lib/PushTask.php View File

@ -3,32 +3,32 @@ use BarnabyWalters\Mf2;
class PushTask { class PushTask {
public static function verify_subscription($subscription_id) {
public static function verify_subscription($subscription_id, $mode) {
$subscription = db\get_by_id('subscriptions', $subscription_id); $subscription = db\get_by_id('subscriptions', $subscription_id);
if($subscription) { if($subscription) {
$feed = db\get_by_id('feeds', $subscription->feed_id); $feed = db\get_by_id('feeds', $subscription->feed_id);
$url = parse_url($subscription->callback_url);
// Choose the expiration for the subscription // Choose the expiration for the subscription
$lease_seconds = 86400*3; $lease_seconds = 86400*3;
$exp_ts = time() + $lease_seconds; $exp_ts = time() + $lease_seconds;
$exp_date = date('Y-m-d H:i:s', $exp_ts); $exp_date = date('Y-m-d H:i:s', $exp_ts);
$push_params = [ $push_params = [
'hub.mode' => 'subscribe',
'hub.mode' => ($mode == 'subscribe' ?an> 'subscribe' : 'unsubscribe'),
'hub.topic' => $feed->feed_url, 'hub.topic' => $feed->feed_url,
'hub.challenge' => $subscription->challenge,
'hub.lease_seconds' => $lease_seconds
'hub.challenge' => $subscription->challenge
]; ];
if($mode == 'subscribe') {
$push_params['hub.lease_seconds'] = $lease_seconds;
}
$url = parse_url($subscription->callback_url);
if($q=k($url, 'query')) { if($q=k($url, 'query')) {
parse_str($q, $existing_params); parse_str($q, $existing_params);
$push_params = array_merge($push_params, $existing_params); $push_params = array_merge($push_params, $existing_params);
} }
$url['query'] = http_build_query($push_params); $url['query'] = http_build_query($push_params);
$url = build_url($url); $url = build_url($url);
$response = request\get_url($url, true); $response = request\get_url($url, true);
@ -37,22 +37,30 @@ class PushTask {
if(request\response_is($response['status'], 2) && $response['body'] == $subscription->challenge) { if(request\response_is($response['status'], 2) && $response['body'] == $subscription->challenge) {
// The subscriber replied with a 2xx status code and confirmed the challenge string. // The subscriber replied with a 2xx status code and confirmed the challenge string.
// The subscription is confirmed and active.
$subscription->date_confirmed = db\now();
$subscription->lease_seconds = $lease_seconds;
$subscription->date_expires = $exp_date;
db\set_updated($subscription);
$subscription->active = 1;
if($mode == 'subscribe') {
// The subscription is confirmed and active.
$subscription->date_confirmed = db\now();
$subscription->lease_seconds = $lease_seconds;
$subscription->date_expires = $exp_date;
$subscription->active = 1;
echo "Subscriber verified the request and is now subscribed\n";
} else {
$subscription->date_unsubscribed = db\now();
$subscription->active = 0;
echo "Subscriber verified the request and is now unsubscribed\n";
}
} else { } else {
// The subscriber did not confirm the subscription, so reject it
// The subscriber did not confirm the subscription, so reject the request
echo "Subscriber did not echo the challenge\n";
} }
db\set_updated($subscription);
$subscription->save(); $subscription->save();
print_r($response); print_r($response);
} }
} }

+ 11
- 0
lib/db_helpers.php View File

@ -41,6 +41,17 @@ function find_or_create($table, $where, $defaults, $autosave=false) {
return $item; return $item;
} }
function find($table, $where) {
$item = ORM::for_table($table);
// Where is an associative array of key/val combos
foreach($where as $c=>$v) {
$item = $item->where($c, $v);
}
return $item->find_one();
}
function feed_from_url($url) { function feed_from_url($url) {
return ORM::for_table('feeds')->where('feed_url', $url)->find_one(); return ORM::for_table('feeds')->where('feed_url', $url)->find_one();
} }

Loading…
Cancel
Save