From 63ce11ef708fc96c09920ba3e2a126072f7f5308 Mon Sep 17 00:00:00 2001 From: James Adam Date: Fri, 8 Mar 2013 22:23:27 +0000 Subject: [PATCH] Spike towards server-controlled immediate printing. This relates to #8, and explores using a single encoded header to simplify parsing of more complex parameters from the server. --- config.ru | 2 + lib/printer/backend_server.rb | 3 ++ .../encoded_status_header_middleware.rb | 21 +++++++++ printer.ino | 21 ++++++--- .../encoded_status_header_middleware_test.rb | 45 +++++++++++++++++++ 5 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 lib/printer/backend_server/encoded_status_header_middleware.rb create mode 100644 test/backend_server/encoded_status_header_middleware_test.rb diff --git a/config.ru b/config.ru index 6820f38..ddab10f 100644 --- a/config.ru +++ b/config.ru @@ -10,6 +10,8 @@ Sass::Plugin.options[:template_location] = 'public/stylesheets' use Sass::Plugin::Rack use Rack::MethodOverride +use Printer::BackendServer::EncodedStatusHeaderMiddleare +use Rack::ContentLength if ENV["RESQUE_SERVER"] require 'resque/server' diff --git a/lib/printer/backend_server.rb b/lib/printer/backend_server.rb index 3f2779b..a45d0c5 100644 --- a/lib/printer/backend_server.rb +++ b/lib/printer/backend_server.rb @@ -7,6 +7,9 @@ module Printer::BackendServer autoload :Settings, "printer/backend_server/settings" autoload :Archive, "printer/backend_server/archive" + autoload :EncodedStatusHeaderMiddleware, + "printer/backend_server/encoded_status_header_middleware" + App = Rack::Builder.new do map("/printer") { run Printer::BackendServer::Polling } map("/preview") { run Printer::BackendServer::Preview } diff --git a/lib/printer/backend_server/encoded_status_header_middleware.rb b/lib/printer/backend_server/encoded_status_header_middleware.rb new file mode 100644 index 0000000..802deae --- /dev/null +++ b/lib/printer/backend_server/encoded_status_header_middleware.rb @@ -0,0 +1,21 @@ +class Printer::BackendServer::EncodedStatusHeaderMiddleware + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers.merge!("X-Printer-Encoded-Status" => encoded_status(status, headers)) + [status, headers, body] + end + + private + + def encoded_status(status, headers) + [status, headers["Content-length"], encoded_presence(headers["X-Printer-PrintImmediately"])].compact.join("|") + end + + def encoded_presence(header) + header ? 1 : 0 + end +end diff --git a/printer.ino b/printer.ino index 6266953..dd65051 100644 --- a/printer.ino +++ b/printer.ino @@ -154,6 +154,7 @@ boolean downloadWaiting = false; char cacheFilename[] = "TMP"; unsigned long content_length = 0; boolean statusOk = false; +boolean printImmediately = false; void checkForDownload() { unsigned long length = 0; @@ -183,19 +184,25 @@ void checkForDownload() { client.println(); boolean parsingHeader = true; + char header[2000]; + while(client.connected()) { while(client.available()) { if (parsingHeader) { - client.find((char*)"HTTP/1.1 "); - char statusCode[] = "xxx"; - client.readBytes(statusCode, 3); - statusOk = (strcmp(statusCode, "200") == 0); - client.find((char*)"Content-Length: "); + client.find((char*)"X-Printer-Encoded-Status: "); + char *buffer = "xxxxxxxxxx"; + client.readBytesUntil('|', buffer, 100); + statusOk = (strcmp(buffer, "200") == 0); + client.readBytesUntil('|', buffer, 100); char c; while (isdigit(c = client.read())) { content_length = content_length*10 + (c - '0'); } - debug2("Content length: ", content_length); + debug2("Content-length: ", content_length); + if (client.readBytesUntil('\n', buffer, 5)) { + printImmediately = (buffer[0] == '1'); + } + debug2("Print immediately: ", printImmediately); client.find((char*)"\n\r\n"); // the first \r may already have been read above parsingHeader = false; } else { @@ -285,7 +292,7 @@ Bounce bouncer = Bounce(buttonPin, 5); // 5 millisecond debounce void loop() { if (downloadWaiting) { bouncer.update(); - if (bouncer.read() == HIGH) { + if (bouncer.read() == HIGH || printImmediately) { printFromDownload(); } } else { diff --git a/test/backend_server/encoded_status_header_middleware_test.rb b/test/backend_server/encoded_status_header_middleware_test.rb new file mode 100644 index 0000000..82b10f0 --- /dev/null +++ b/test/backend_server/encoded_status_header_middleware_test.rb @@ -0,0 +1,45 @@ +require "test_helper" +require "rack/test" +require "printer/backend_server" + +ENV['RACK_ENV'] = 'test' + +describe Printer::BackendServer::EncodedStatusHeaderMiddleware do + include Rack::Test::Methods + + def app + Rack::Builder.new do + use Printer::BackendServer::EncodedStatusHeaderMiddleware + use Rack::ContentLength + run lambda { |env| + headers = env["PATH_INFO"] == "/print-now" ? {"X-Printer-PrintImmediately" => true} : {} + [200, headers, ["Response body"]] + } + end + end + + describe "making a request" do + before do + get "anything" + end + + it "includes the encoded header" do + assert last_response.headers.keys.include?("X-Printer-Encoded-Status") + end + + it "encodes the status in the header" do + last_response.headers["X-Printer-Encoded-Status"].split("|")[0].must_equal "200" + end + + it "encodes the content length in the header" do + last_response.headers["X-Printer-Encoded-Status"].split("|")[1].must_equal "Response body".length.to_s + end + end + + describe "making a request where the X-Printer-PrintImmediately header is present" do + it "encodes the print immediately value into the header" do + get "/print-now" + last_response.headers["X-Printer-Encoded-Status"].split("|")[2].must_equal "1" + end + end +end