diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Templates.class.php | 120 | ||||
-rw-r--r-- | UrlGenerator.class.php | 10 | ||||
-rw-r--r-- | db.php | 63 | ||||
-rw-r--r-- | endpoint.php | 1 | ||||
-rw-r--r-- | queue.php | 173 |
6 files changed, 319 insertions, 49 deletions
@@ -1 +1,2 @@ .*.un~ +.*.swp diff --git a/Templates.class.php b/Templates.class.php new file mode 100644 index 0000000..9cfec4f --- /dev/null +++ b/Templates.class.php @@ -0,0 +1,120 @@ +<?php + +include_once "db.php"; + +function apply() { + $args = func_get_args(); + $f = $args[0]; + $args = array_slice($args, 1); + return function() use ($f, $args) { + return call_user_func_array($f, $args); + }; +} + +// Queue List + +function template_queue_list_text($url_generator, array $queues) { + $count = count($queues); +?> +Number of queues: <?=$count?>. + +<?php + foreach($queues as $q) { + echo($q->toPlainText($url_generator) . "\n"); + } +} + +function template_queue_list_html(UrlGenerator $url_generator, array $queues) { + html_default(apply("render_queues", $url_generator, $queues)); +} + +function render_queues($url_generator, $queues) { + $count = count($queues); +?> +<p> +Number of queues: <?=$count?>. +</p> + +<?php + foreach($queues as $q) { + echo($q->toHtml($url_generator, FALSE) . "\n"); + } +} + + +// Queue + +function template_queue_html(UrlGenerator $url_generator, Queue $queue) { + html_default(apply("render_queue_html", $url_generator, $queue)); +} + +function render_queue_html(UrlGenerator $url_generator, Queue $queue) { + echo url_to_a($url_generator->queues(), "All queues"); + echo $queue->toHtml($url_generator, TRUE); +} + +function template_queue_text(UrlGenerator $url_generator, Queue $queue) { + echo($queue->toPlainText($url_generator)); +} + +// Item List + +function template_item_list_html(UrlGenerator $url_generator, $queue, array $items) { + html_default(apply("render_item_list_html", $url_generator, $queue, $items)); +} + +function render_item_list_html(UrlGenerator $url_generator, $queue, array $items) { + $queue_url = url_to_a($url_generator->queue($queue)); + $html = + "<h1>Items in $queue</h1>" . + "<ul>" . + "<li>$queue_url</li>" . + "<li>Queue has " . count($items) . " items.</li>" . + "</ul>"; + echo $html; + + foreach($items as $item) { + echo($item->toHtml($url_generator)); + } +} + +function template_item_list_text(UrlGenerator $url_generator, $queue, array $items) { + echo("This queue has " . count($items) . " items.\n"); + echo("\n"); + + foreach($items as $item) { + echo($item->toPlainText($url_generator)); + echo("\n"); + } +} + +// Common + +function invoke($f) { + if(is_callable($f)) { + $f(); + } + else { + echo($f); + } +} + +function html_default($body, $head = NULL) { +?> +<html> +<head> +<?php +if($head != NULL) { + $head(); +} +?> +</head> +<body> +<?php +invoke($body); +?> +</body> +</html> +<?php +} +?> diff --git a/UrlGenerator.class.php b/UrlGenerator.class.php index 03c5b14..24aa75e 100644 --- a/UrlGenerator.class.php +++ b/UrlGenerator.class.php @@ -6,16 +6,24 @@ class UrlGenerator { $this->baseurl = $baseurl; } + function queues() { + return $this->baseurl . "/queue"; + } + function queue($queue) { return $this->baseurl . "/queue/" . $queue; } + function queue_items($queue) { + return $this->baseurl . "/queue/" . $queue . "/items"; + } + function enqueue($queue) { return $this->baseurl . "/enqueue/" . $queue; } function item($queue, $item) { - return $this->baseurl . "/item/" . $queue . "/" . $id; + return $this->baseurl . "/queue/" . $queue . "/items/" . $item; } function item_enclosure($queue, $id) { @@ -1,13 +1,40 @@ <?php +function url_to_a($url, $title = NULL) { + if(!isset($title)) { + $title = htmlspecialchars($url); + } + return "<a href='" . htmlspecialchars($url) . "'>$title</a>"; +} + class Queue { public $name; public $endpoint_url; function toPlainText($url_generator) { return "Name: " . $this->name . "\n" . + "Queue URL: " . $url_generator->queue($this->name) . "\n" . "Endpoint URL: " . (isset($this->endpoint_url) ? $this->endpoint_url : "Not set") . "\n" . - "Enqueue: " . $url_generator->enqueue($this->name) . "\n"; + "Enqueue: " . $url_generator->enqueue($this->name) . "\n" . + "Items: " . $url_generator->queue_items($this->name) . "\n"; + } + + function toHtml($url_generator, $detail) { + $queue_url = url_to_a($url_generator->queue($this->name)); + $endpoint = !isset($this->endpoint_url) ? "Not set" : htmlspecialchars($this->endpoint_url); + $enqueue_url = url_to_a($url_generator->enqueue($this->name)); + $items_url = url_to_a($url_generator->queue_items($this->name)); + $html = + "<h2>Queue: $this->name</h2>" . + "<table>" . + "<tr><td>Queue URL</td><td>$queue_url</td></tr>"; + if($detail) $html .= + "<tr><td>Endpoint URL</td><td>$endpoint</td></tr>" . + "<tr><td>Enqueue</td><td>$enqueue_url</td></tr>" . + "<tr><td>Items</td><td>$items_url</td></tr>"; + $html .= + "</table>"; + return $html; } static function valid_name($str) { @@ -39,6 +66,24 @@ class Item { } return "Headers:\n" . $headers; } + + function toHtml($url_generator) { + $item_url = url_to_a($url_generator->item($this->queue_name, $this->id)); + $html = + "<h2>Item</h2>" . + "<h3>Meta</h3>" . + "<ul>" . + "<li>Id: $this->id</li>" . + "<li>Created: $this->created</li>" . + "<li>Link: $item_url</li>" . + "</ul>" . + "<h3>Headers</h3>" . + "<ul>\n"; + foreach($this->headers as $k => $v) { + $html .= "<li>" . $k . ": " . $v . "</li>\n"; + } + return $html . "</ul>\n"; + } } class DB { @@ -100,7 +145,15 @@ class DB { $stmt->setFetchMode(PDO::FETCH_CLASS, "Queue"); $stmt->bindParam(":name", $queue); $stmt->execute(); - return $stmt->fetch(PDO::FETCH_CLASS); + $x = $stmt->fetch(PDO::FETCH_CLASS); + return $x === FALSE ? NULL : $x; + } + + function delete_item($queue_name, $id) { + $stmt = $this->db->prepare("DELETE FROM item WHERE queue_name = :queue_name AND id = :id"); + $stmt->bindParam(":queue_name", $queue_name); + $stmt->bindParam(":id", $id); + $stmt->execute(); } function select_item($queue_name, $id) { @@ -108,7 +161,8 @@ class DB { $stmt->bindParam(":queue_name", $queue_name); $stmt->bindParam(":id", $id); $stmt->execute(); - return $stmt->fetchAll(PDO::FETCH_FUNC, 'item_from_db'); + $x = $stmt->fetchAll(PDO::FETCH_FUNC, 'item_from_db'); + return count($x) > 0 ? $x[0] : NULL; } function select_items($queue_name, $limit = 10, $offset = 0) { @@ -117,7 +171,8 @@ class DB { $stmt->bindParam(":limit", $limit); $stmt->bindParam(":offset", $offset); $stmt->execute(); - return $stmt->fetchAll(PDO::FETCH_FUNC, 'item_from_db'); + $x = $stmt->fetchAll(PDO::FETCH_FUNC, 'item_from_db'); + return $x; } } diff --git a/endpoint.php b/endpoint.php index e133c90..b8f9f6c 100644 --- a/endpoint.php +++ b/endpoint.php @@ -29,6 +29,7 @@ if(isset($content_length)) { fwrite($fd, "Content-Length: ". $content_length . "\n"); } fwrite($fd, "\n"); +fwrite($fd, file_get_contents("php://input")); fflush($fd); fclose($fd); @@ -1,6 +1,7 @@ <?php include_once "db.php"; include_once "UrlGenerator.class.php"; +include_once "Templates.class.php"; header("Content-Type: text/plain"); @@ -12,9 +13,10 @@ function data_file($id) { return "/tmp/mq/data/$id"; } -/* -var_dump($_SERVER); -*/ +function log_file($id) { + return "/tmp/mq/data/" . $id . ".log"; +} + $method = $_SERVER["REQUEST_METHOD"]; $content_type = isset($_SERVER["CONTENT_TYPE"]) ? $_SERVER["CONTENT_TYPE"] : NULL; $db = new DB(); @@ -29,7 +31,7 @@ if(isset($content_type) && $content_type == "application/x-www-form-urlencoded") list($key, $value) = split("=", $part); $form[$key] = $value; } - var_dump($form); +// var_dump($form); } $path_info = $_SERVER["PATH_INFO"]; @@ -41,7 +43,10 @@ else { $path_info = preg_replace('/[\/]$/', '', $path_info); $path_info = preg_replace('/^[\/]/', '', $path_info); $segments = explode("/", $path_info); - $baseurl = "http://" . $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["SCRIPT_NAME"]; +// var_dump($segments); + $port = $_SERVER["SERVER_PORT"]; + $port = $port == "80" ? "" : ":" . $port; + $baseurl = "http://" . $_SERVER["SERVER_NAME"] . $port . $_SERVER["SCRIPT_NAME"]; $url_generator = new UrlGenerator($baseurl); switch($segments[0]) { case "enqueue": @@ -51,20 +56,23 @@ else { } enqueue($url_generator, $segments[1]); break; - case "item": - allow_methods("GET"); - if(count($segments) != 3) { - not_found(); - } - item($url_generator, $segments[1], $segments[2]); - break; case "queue": switch(count($segments)) { case 1: - queue($url_generator); + queues($url_generator); break; case 2: - queues($url_generator, $segments[1]); + queue($url_generator, $segments[1]); + break; + case 3: + if($segments[2] == "items") { + items($url_generator, $segments[1]); + } + break; + case 4: + if($segments[2] == "items") { + item($url_generator, $segments[1], $segments[3]); + } break; default: not_found(); @@ -126,6 +134,17 @@ function bad_request($short = NULL, $long = NULL) { exit(0); } +function conneg() { + $accept = isset($_SERVER["HTTP_ACCEPT"]) ? $_SERVER["HTTP_ACCEPT"] : NULL; + // First media type + $accept = preg_replace('/^([^,]*),.*/', '$1', $accept); +// var_dump($accept); + // Remove parameters + $accept = preg_replace('/^([^;]*);.*/', '$1', $accept); +// var_dump($accept); + return $accept; +} + function cron() { global $db; @@ -152,6 +171,18 @@ function cron() { function process_item($queue, $item) { echo("Processing item " . $item->id . " from queue " . $queue->name . "\n"); + $input_path = data_file($item->id); + $input_fd = fopen($input_path, "r"); + + $log_path = log_file($item->id); + $log_fd = fopen($log_path, "w"); + + if(!$input_fd || !$log_fd) { + echo("Error opening " . $path . "\n"); + fclose($input_fd); + fclose($log_fd); + return; + } $handle = curl_init(); // http://no2.php.net/manual/en/function.curl-setopt.php @@ -170,26 +201,34 @@ function process_item($queue, $item) { curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 1); // Return the transfer as a string of the return value of curl_exec() - curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); +// curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); // In seconds curl_setopt($handle, CURLOPT_TIMEOUT, 30); curl_setopt($handle, CURLOPT_URL, $queue->endpoint_url); - var_dump($item->headers); - curl_setopt($handle, CURLOPT_HEADER, $item->headers); + curl_setopt($handle, CURLOPT_HTTPHEADER, $item->headers); + curl_setopt($handle, CURLOPT_INFILE, $input_fd); + + curl_setopt($handle, CURLOPT_WRITEHEADER, $log_fd); + curl_setopt($handle, CURLOPT_FILE, $log_fd); + curl_setopt($handle, CURLOPT_STDERR, $log_fd); - curl_setopt($handle, CURLOPT_INFILE, data_file($item->id)); + curl_setopt($handle, CURLOPT_CUSTOMREQUEST, "POST"); + echo("Executing request...\n"); + fwrite($log_fd, "POST " . $queue->endpoint_url . "\n"); $ret = curl_exec($handle); + if($ret === false) { - echo("curl failed"); - echo("error: " . curl_error($handle)); + echo("curl failed\n"); + echo("error: " . curl_error($handle) . "\n"); } else { - echo("curl success"); - echo($ret); + echo("curl success\n"); } + fclose($input_fd); + fclose($log_fd); curl_close($handle); } @@ -219,25 +258,62 @@ function enqueue($url_generator, $queue) { $db->insert_item($id, $headers, array($queue)); header("HTTP/1.1 201 Created as " . $id); - header("Location: " . $url_generator->item($id)); + header("Location: " . $url_generator->item($queue, $id)); } catch (Exception $e) { header("HTTP/1.1 500 Error"); echo("Caught exception: " . $e->getMessage() . "\n"); } } -function item($url_generator, $queue, $id) { - global $db; +function item($url_generator, $queue, $item) { + global $db, $method; + + list($x, $queue, $id) = $segments; $item = $db->select_item($queue, $id); -// var_dump($item); - $item = $item[0]; - header("Link: <" . $url_generator->item_enclosure($item->id) . ">;rel=enclosure"); - echo("Showing: " . $item->id . "\n"); - echo($item->toPlainText($url_generator)); + if($item == NULL) { + not_found("No such item: " . $id); + } + + switch($method) { + case "GET": + header("Link: <" . $url_generator->item_enclosure($item->id) . ">;rel=enclosure"); + echo("Showing: " . $item->id . "\n"); + echo($item->toPlainText($url_generator)); + break; + case "DELETE": + $db->delete_item($queue, $id); + @unlink(data_file($id)); + @unlink(log_file($id)); + header("HTTP/1.1 204 Deleted item " . $id); + break; + default: + allow_methods("GET", "DELETE"); + break; + } +} + +function items($url_generator, $queue) { + global $db; + + allow_methods("GET"); + + header("HTTP/1.1 200 Items in $queue"); + $items = $db->select_items($queue); + switch(conneg()) { + default: + case "text/plain": + header("Content-Type: text/plain"); + template_item_list_text($url_generator, $queue, $items); + break; + case "text/html": + header("Content-Type: text/html"); + template_item_list_html($url_generator, $queue, $items); + break; + } } -function queue($url_generator) { +function queues($url_generator) { global $method, $content_type, $db; switch($method) { @@ -246,16 +322,16 @@ function queue($url_generator) { $queues = $db->select_queues(); $count = count($queues); - header("Content-Type: text/plain"); - if($count == 1) { - echo("Have one queue"); - } - else { - echo("Have " . $count . " queues"); - } - echo("\n\n"); - foreach($queues as $q) { - echo($q->toPlainText($url_generator) . "\n"); + switch(conneg()) { + default: + case "text/plain": + header("Content-Type: text/plain"); + template_queue_list_text($url_generator, $queues); + break; + case "text/html": + header("Content-Type: text/html"); + template_queue_list_html($url_generator, $queues); + break; } break; case "POST": @@ -278,7 +354,7 @@ function queue($url_generator) { } } -function queues($url_generator, $queue) { +function queue($url_generator, $queue) { global $method, $content_type, $form, $db; if(!Queue::valid_name($queue)) { @@ -293,8 +369,17 @@ function queues($url_generator, $queue) { not_found("No such queue: " . $queue); } - header("Content-Type: text/plain"); - echo($q->toPlainText($url_generator)); + switch(conneg()) { + case "text/html"; + header("Content-Type: text/html"); + template_queue_html($url_generator, $q); + break; + default: + case "text/plain"; + header("Content-Type: text/plain"); + template_queue_text($url_generator, $q); + break; + } break; case "PUT": $q = $db->select_queue($queue); |