Skip to content

Commit

Permalink
Merge pull request #35 from xp-forge/feature/dev-console
Browse files Browse the repository at this point in the history
Development console
  • Loading branch information
thekid authored Feb 12, 2018
2 parents 1404300 + 1d03457 commit 6fde8cf
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 7 deletions.
10 changes: 10 additions & 0 deletions src/main/php/web/Application.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ public final function routing() {
*/
protected abstract function routes();

/**
* Installs global filters
*
* @param web.Filter[] $filters
* @return void
*/
public function install($filters) {
$this->routing= Routing::cast(new Filters($filters, $this->routing()));
}

/**
* Service delegates to the routing, calling its `service()` method.
*
Expand Down
7 changes: 6 additions & 1 deletion src/main/php/xp/web/SAPI.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ public function scheme() { return 'http'; }
public function uri() { return $_SERVER['REQUEST_URI']; }

/** @return [:string] */
public function headers() { return getallheaders(); }
public function headers() {
yield 'Remote-Addr' => $_SERVER['REMOTE_ADDR'];
foreach (getallheaders() as $name => $value) {
yield $name => $value;
}
}

/** @return string */
public function readLine() {
Expand Down
15 changes: 12 additions & 3 deletions src/main/php/xp/web/Source.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,23 @@ class Source {
/**
* Creates a new application from a given name and environment
*
* @param string $name
* @param string $name `application[+filter[,filter[,...]]]`
* @param web.Environment $environment
*/
public function __construct($name, $environment) {
if ('-' === $name) {
sscanf($name, '%[^+]+%s', $application, $filters);

if ('-' === $application) {
$this->application= new ServeDocumentRootStatically($environment);
} else {
$this->application= XPClass::forName($name)->newInstance($environment);
$this->application= XPClass::forName($application)->newInstance($environment);
}

if ($filters) {
$this->application->install(array_map(
function($filter) { return XPClass::forName($filter)->newInstance(); },
explode(',', $filters)
));
}
}

Expand Down
31 changes: 31 additions & 0 deletions src/main/php/xp/web/dev/Buffer.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php namespace xp\web\dev;

use web\io\Output;

class Buffer extends Output {
public $status, $message, $headers;
public $bytes= '';

public function begin($status, $message, $headers) {
$this->status= $status;
$this->message= $message;
$this->headers= $headers;
}

public function write($bytes) {
$this->bytes.= $bytes;
}

/**
* Drain this buffered output to a given output instance, closing it
* once finished.
*
* @param web.io.Output $out
* @return void
*/
public function drain(Output $out) {
$out->begin($this->status, $this->message, $this->headers);
$out->write($this->bytes);
$out->close();
}
}
74 changes: 74 additions & 0 deletions src/main/php/xp/web/dev/Console.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php namespace xp\web\dev;

use web\Filter;
use web\Response;

/**
* The development console captures content written via `var_dump()`,
* `echo` or other builtin output statements and - if any - displays it
* inside an easily readable format above the real output, using a 200
* HTTP response status.
*
* @see php://ob_start
*/
class Console implements Filter {
private $template;

/** @param string $name */
public function __construct($name= 'xp/web/dev/console') {
$this->template= $name.'.html';
}

/**
* Creates HTML table rows
*
* @param [:var] $headers
* @return string
*/
private function rows($headers) {
$r= '';
foreach ($headers as $name => $value) {
$r.= '<tr>
<td class="name">'.htmlspecialchars($name).'</td>
<td class="value">'.htmlspecialchars(implode(', ', $value)).'</td>
</tr>';
}
return $r;
}

/**
* Filters the request
*
* @param web.Request $req
* @param web.Response $res
* @param web.filters.Invocation $invocation
* @return var
*/
public function filter($req, $res, $invocation) {
$buffer= new Buffer();

try {
ob_start();
$result= $invocation->proceed($req, new Response($buffer));
} finally {
$debug= ob_get_clean();
ob_end_clean();
}

if (empty($debug)) {
$buffer->drain($res->output());
} else {
$res->status(200, 'Debug');
$res->send(sprintf(
typeof($this)->getClassLoader()->getResource($this->template),
htmlspecialchars($debug),
$buffer->status,
htmlspecialchars($buffer->message),
$this->rows($buffer->headers),
htmlspecialchars($buffer->bytes)
));
}

return $result;
}
}
68 changes: 68 additions & 0 deletions src/main/php/xp/web/dev/console.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html>
<head>
<title>Debug</title>
<style type="text/css">
body { font-family: "Segoe UI",Arial,Helvetica; background-color: rgb(27, 43, 52); color: rgb(205, 211, 222); }
#content { margin: 2em; }
h1 img { float: left; margin-right: 0.5em; }
h1 #code { padding: 0.1em 0.5em; background-color: rgb(102, 153, 204); color: white; border-radius: 0.1em; }
#debug { border: 1px dotted rgb(205, 211, 222); overflow: hidden; padding: 0.5em; font-size: 13px; }
button.clip { float: right; }
h2 #status { color: rgb(102, 153, 204); }
table { margin-bottom: 1.5em; }
td { padding: 0.3em; }
td.name { background-color: rgb(41, 56, 65); }
td.value { color: rgb(249, 145, 87); font-family: monospace; font-size: 13px; }
button { background-color: rgb(41, 56, 65); cursor: pointer; border-radius: 0.1em; border: none; }
button:hover { opacity: .65; transition: all 150ms linear; }
</style>
</head>
<body bgcolor="#ffffff" text="#000000">
<div id="content">
<h1>
<img width="59" height="48" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAAAwCAYAAACv4gJwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAEeSURBVGhD7ZdNCsIwEEaj1/AILvUCHsStuPIwrsStB/EEnkmTkoESMklq85/vgQwFS+frm2npZrc/fsUgbHUdAoTtFYTtFW/Y0+3RVHXBvnrUye/7VR+1g6tvvGdDRqJmuP6HMmsNG7qvJSYgtC/b/6xj3OKDac6iB5TPLBl9XQ5Tzcn5+Zmqrz+YjWGW7nZKzGvBrIbrP+p7Vt19+tFxCbj+o5tVY0ajpmqJwFnMKkyzOfbZJItZsjo3W4JsZmsg287WAMxKYBZmGwJmJUOZxfcszFrgdiMloX3B7BqzIZB9136H7OESYFaSzCwZ/YcY14bZ1DtbAq5/a9hesY6xYs3OlcTVNxuWxoBObqW61g9j3CsI2ysI2ysDhRXiB5CuA+ASNuP/AAAAAElFTkSuQmCC" alt="Debug"/>

<span id="code">DEBUG</span>
</h1>
<div id="debug">
<button class="clip" title="Copy to clipboard" onclick="clip(document.getElementById('output').innerText); flash(document.getElementById('debug'))">📋</button>
<pre id="output">%1$s</pre>
</div>

<!-- Original HTTP response -->
<h2>HTTP/1.1 <span id="status">%2$d %3$s</span></h2>
<table id="headers">
%4$s
</table>
<pre id="body">%5$s</pre>
</div>
<script type="text/javascript">
function clip(text) {
if (window.clipboardData) {
window.clipboardData.setData('Text', text);
} else {
var t = document.createElement('textarea');
t.value = text;
t.style.position = 'fixed';
t.style.top = 0;
t.style.left = 0;
t.style.width = '2em';
t.style.height = '2em';
t.style.background = 'transparent';
t.style.border = 'none';
document.body.appendChild(t);
t.select();
document.execCommand('copy');
document.body.removeChild(t);
}
}

function flash(div) {
div.style.transition = 'all 150ms linear';
div.style.backgroundColor = 'rgb(41, 56, 65)';
setTimeout(function() { div.style.backgroundColor = null; }, 100);
}
</script>
</body>
</html>
4 changes: 2 additions & 2 deletions src/main/php/xp/web/srv/Develop.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use peer\Socket;
use io\IOException;

class Develop {
class Develop implements Server {
private $host, $port;

/**
Expand Down Expand Up @@ -61,7 +61,7 @@ public function serve($source, $profile, $webroot, $docroot, $config) {
// Export environment
putenv('DOCUMENT_ROOT='.$docroot);
putenv('SERVER_PROFILE='.$profile);
putenv('WEB_SOURCE='.$source);
putenv('WEB_SOURCE='.$source.'+xp.web.dev.Console');
putenv('WEB_CONFIG='.implode('PATH_SEPARATOR', $config));
putenv('WEB_ROOT='.$webroot);

Expand Down
15 changes: 15 additions & 0 deletions src/main/php/xp/web/srv/Server.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php namespace xp\web\srv;

interface Server {

/**
* Serve requests
*
* @param string $source
* @param string $profile
* @param io.Path $webroot
* @param io.Path $docroot
* @param string[] $config
*/
public function serve($source, $profile, $webroot, $docroot, $config);
}
2 changes: 1 addition & 1 deletion src/main/php/xp/web/srv/Standalone.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use web\Environment;
use xp\web\Source;

abstract class Standalone {
abstract class Standalone implements Server {
private $server, $url;

public function __construct($server, $url) {
Expand Down

0 comments on commit 6fde8cf

Please sign in to comment.