Browse Source

push subscriptions

master
Aaron Parecki 6 years ago
parent
commit
273fe3cf5b
7 changed files with 147 additions and 40 deletions
  1. +1
    -0
      composer.json
  2. +6
    -6
      composer.lock
  3. +42
    -31
      controllers/push.php
  4. +3
    -3
      lib/DeferredTask.php
  5. +57
    -0
      lib/PushTask.php
  6. +7
    -0
      lib/db_helpers.php
  7. +31
    -0
      scripts/run.php

+ 1
- 0
composer.json View File

@ -18,6 +18,7 @@
"lib/db_helpers.php",
"lib/mf2_feed_parser.php",
"lib/DeferredTask.php",
"lib/PushTask.php",
"lib/request.php"
]
}

+ 6
- 6
composer.lock View File

@ -4,7 +4,7 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "e97be02376b6b07beab7c771b815ca64",
"hash": "56d03ce1ea73dfa3bd0f68bf4a987844",
"packages": [
{
"name": "barnabywalters/mf-cleaner",
@ -48,16 +48,16 @@
},
{
"name": "indieauth/client",
"version": "0.1.8",
"version": "0.1.9",
"source": {
"type": "git",
"url": "https://github.com/indieweb/indieauth-client-php.git",
"reference": "f979f8ee0fc6daaa6a393e7afdac894000d09544"
"reference": "6f9303cb79de7f650018cb8a317798bd4bfc2fb9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/f979f8ee0fc6daaa6a393e7afdac894000d09544",
"reference": "f979f8ee0fc6daaa6a393e7afdac894000d09544",
"url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/6f9303cb79de7f650018cb8a317798bd4bfc2fb9",
"reference": "6f9303cb79de7f650018cb8a317798bd4bfc2fb9",
"shasum": ""
},
"require": {
@ -83,7 +83,7 @@
}
],
"description": "IndieAuth Client Library",
"time": "2014-10-06 07:37:10"
"time": "2015-03-18 20:00:10"
},
{
"name": "indieweb/link-rel-parser",

+ 42
- 31
controllers/push.php View File

@ -6,6 +6,21 @@ function push_error(&$app, $msg) {
die();
}
///////////////////////////////////////////////////////////////
// These are just test routes
$app->get('/callback-success', function() use($app) {
$params = $app->request()->params();
$app->response()->status(200);
echo $params['hub_challenge'];
});
$app->get('/callback-fail', function() use($app) {
$params = $app->request()->params();
$app->response()->status(404);
});
///////////////////////////////////////////////////////////////
$app->post('/', function() use($app) {
$params = $app->request()->params();
@ -24,41 +39,37 @@ $app->post('/', function() use($app) {
push_error($app, 'Callback URL was invalid');
}
// Make a HEAD request to the topic URL to check if it exists
$topic_head = request\get_head($topic);
if($topic_head) {
if(request\response_is($topic_head['status'], 2)) {
$app->response()->status(202);
// Find or create the feed given the topic URL
$feed = db\find_or_create('feeds', ['feed_url'=>$topic], [
'hash' => db\random_hash(),
], true);
print_r($feed);
// 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(),
]);
$subscription->date_requested = db\now();
$subscription->challenge = db\random_hash();
$subscription->save();
echo "The subscription request is being validated. Check the status here:\n";
echo Config::$base_url . '/subscription/' . $subscription->hash . "\n";
// 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 {
$app->response()->status(400);
echo "The topic URL returned a " . $topic_head['status'] . " status code\n";
push_error($app, 'We tried to verify the topic URL exists but it didn\'t respond to a HEAD request.');
}
} else {
push_error($app, 'There was a problem trying to verify the topic URL');
}
// 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);
$app->response()->status(202);
echo "The subscription request is being validated. Check the status here:\n";
echo Config::$base_url . '/subscription/' . $subscription->hash . "\n";
break;
case 'unsubscribe':

+ 3
- 3
lib/DeferredTask.php View File

@ -5,7 +5,7 @@ class DeferredTask {
public static function run() {
global $pcntl_continue;
$tube = 'monocle-worker';
$tube = 'switchboard-worker';
echo "PID " . posix_getpid() . " watching tube: " . $tube . "\n";
bs()->watch($tube)->ignore('default');
@ -29,7 +29,7 @@ class DeferredTask {
}
public static function run_once() {
$tube = 'monocle-worker';
$tube = 'switchboard-worker';
echo "PID " . posix_getpid() . " watching tube: " . $tube . "\n";
bs()->watch($tube)->ignore('default');
@ -44,7 +44,7 @@ class DeferredTask {
if(!is_array($args))
$args = array($args);
bs()->putInTube('monocle-worker',
bs()->putInTube('switchboard-worker',
json_encode(array('class'=>$class, 'method'=>$method, 'args'=>$args)),
1024, // priority
$delay, // delay

+ 57
- 0
lib/PushTask.php View File

@ -0,0 +1,57 @@
<?php
use BarnabyWalters\Mf2;
class PushTask {
public static function verify_subscription($subscription_id) {
$subscription = db\get_by_id('subscriptions', $subscription_id);
if($subscription) {
$feed = db\get_by_id('feeds', $subscription->feed_id);
$url = parse_url($subscription->callback_url);
// Choose the expiration for the subscription
$lease_seconds = 86400*3;
$exp_ts = time() + $lease_seconds;
$exp_date = date('Y-m-d H:i:s', $exp_ts);
$push_params = [
'hub.mode' => 'subscribe',
'hub.topic' => $feed->feed_url,
'hub.challenge' => $subscription->challenge,
'hub.lease_seconds' => $lease_seconds
];
if($q=k($url, 'query')) {
parse_str($q, $existing_params);
$push_params = array_merge($push_params, $existing_params);
}
$url['query'] = http_build_query($push_params);
$url = build_url($url);
$response = request\get_url($url, true);
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 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;
$subscription->save();
} else {
// The subscriber did not confirm the subscription, so reject it
}
print_r($response);
}
}
}

+ 7
- 0
lib/db_helpers.php View File

@ -41,3 +41,10 @@ function find_or_create($table, $where, $defaults, $autosave=false) {
return $item;
}
function feed_from_url($url) {
return ORM::for_table('feeds')->where('feed_url', $url)->find_one();
}
function get_by_id($table, $id) {
return ORM::for_table($table)->where('id', $id)->find_one();
}

+ 31
- 0
scripts/run.php View File

@ -0,0 +1,31 @@
<?php
declare(ticks=1);
chdir('..');
$mode = 'run';
if(array_key_exists(1, $argv) && $argv[1] == 'once')
$mode = 'once';
if($mode == 'run') {
if(function_exists('pcntl_signal')) {
pcntl_signal(SIGINT, function($sig){
global $pcntl_continue;
$pcntl_continue = FALSE;
});
}
}
$pcntl_continue = TRUE;
define('PDO_SUPPORT_DELAYED', TRUE);
// TODO: add support for forking and running many workers in parallel
// e.g. `php run.php 10`
require 'vendor/autoload.php';
if($mode == 'once') {
DeferredTask::run_once();
} else {
DeferredTask::run();
}

Loading…
Cancel
Save