Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery


Published on

Published in: Technology, Business
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Hi, good morning. Welcome to my talk.
  • My name is Tatsuhiko Miyagawa.
  • I work for a company called Six Apart in San Francisco. It’s a company behind many blogging software like Movable Type, Vox and TypePad.
  • I mostly work on TypePad and recently we shipped new services like TypePad Connect and TypePad Profile. I did most of the backend code for those products.
  • This is my CPAN/PAUSE ID and you might have already known my name by:
  • the 154 modules I wrote and uploaded on CPAN. Some of these might look familiar to you.
  • miyagawa is also my twitter ID, and I’ll post links to the slides of this talk to Twitter later. Since this is 20 minute talk and there are many things to talk about, it’ll be pretty fast presentation, you don’t need to take notes or remember URLs and what not. Just look at the slides later online.
  • Let me give you a quick intro of the application called “Remedie” I’ve been working on recently like half an year. I’ll use this application as an example app today.
  • So, long story short, I wanted to build some Desktop applications, with nice UI rather than Command Line interface.
  • There might be many options to build a desktop GUI application. Some MFC/.NET microsoft windows thing. That’s not something you want to learn in 2009.
  • wxWidgets. I think this is a cross platform library to build a GUI application that runs on Windows, Mac and Linux and there’s a perl binding. Padre, PerlIDE actually uses this to build the Perl editor. Might not be a bad choice if you want to build an editor.
  • Objective C and Cocoa API is the best way to build some beautiful looking applications that run on Mac OS X. I guess it’s worth investing your time learning these technologies since you can leverage that to build iPhone applications for instance. And there’re also scripting language glues for Python and Ruby.
  • Adobe AIR would probably be the best choice if you already know some ActionScript and want to build a nice looking GUI app that runs on major platforms.
  • So, all of these options have pros and cons. Some are platform specific and some things need a completely different paradigm and I would need a lot of time learning those stuff. I’m a Perl hacker and do web stuff every day. I know a lot of Perl, and little bit of JavaScript.
  • Why not just build a web application and ship it as a desktop application.
  • Remember when Steve Jobs announced their initial developer SDK for iPhone in 2007. It was Web 2.0 Ajax application that has an access to iPhone services via sandboxed JavaScript APIs.
  • Palm Pre has this operating system called WebOS and its SDK called Mojo SDK allows you to write an application with HTML, CSS and JavaScript.
  • And there’s also a project called PhoneGap that allows you to do the same thing against iPhone, Android and BlackBerry: PhoneGap gives you an abstract wrapper API to access phone device functionalities through JavaScript so you can write an application using HTML, CSS and JavaScript for these devices. Luke used this framework to write his YAPC schedule app for Android.
  • And now HTML5 is coming on its way, with lots of features and APIs to access stuff like Geo location, native video embeds and local storage access.
  • It’s coming, but it hasn’t fully come yet. It’s definitely the future, but not available right now as its final form, in 2009. So what can fill this “gap”, like Phone Gap does?
  • It’s micro web app, or desktop web applications.
  • So let’s get back to this Remedie example and give you a quick demo. This is a pluggable, perl-based media center application that allows you to subscribe to virtually ANY video sites with RSS feeds, or even without RSS feeds if you write plugins. And you can watch videos or photos inline or using external player like QuickTime with single, pretty user interface.
  • Amazing? Cool. Let’s talk about how I built this application using which tools and modules. That’s probably what you’re interested in.
  • HTTP::Engine is based on Catalyst::Engine. It’s an extraction from Catalyst’s HTTP request and response handling code so that you can use it outside Catalyst to write a web application that runs under CGI, FastCGI or standalone server or mod_perl without changing anything. You can also use this to build your own micro web framework.
  • This is the callback function you need to bind the request. It takes an HTTP::Engine::Request object, which has a nice set of APIs to access request headers, cookies and parameters and all of that, and your callback is supposed to return the Response object with headers and body. That’s it.
  • It already has many interfaces supported, mostly ported over from Catalyst. Standalone, POE for event loop asynchronous process, FastCGI and mod_perl. Very nice.
  • So here, we’re making a desktop application. We don’t need a separate web server to serve millions of page views in a minute, so no need for FastCGI or mod_perl thing, right? Let’s just use ServerSimple, or POE if you want non-blocking processing.
  • And here are the things your callback handler is supposed to do. First of all, you need to serve static files to build the user interface. That will be HTML, CSS and JavaScript files.
  • HTTP::Engine has a extension framework called Middleware and they probably have static file serving code, so I’d probably switch to that instead of doing this file manipulation directly, which is kind of insecure.
  • The other thing your controller is supposed to is to implement Ajax backend actions with REST-JSON.
  • Note that this is a simplified code. And yes this is a little insecure.
  • And as I said, the construction to map HTTP request to internal API call is kind of crufty and insecure.
  • There are lots of solution to this, notably Path::Router, Dispatcher and HTTP::Dispatcher. They’re from best practical and Infinity Interactive, so pick whichever company you like. JSORB is also from infinity interactive and does more robust and kind of complicated REST-JSON mappings to call methods in the backend from JS client.
  • And lastly those REST APIs are vulnerable to Cross Site Request Forgery. If a hacker knows which port you’re running your application on, they can just link or send form POST to your endpoint to do whatever they want, using your identity.
  • Some authentication might help, but cookies or basic auth don’t because it’s CSRF. In Remedie we add some special header to the normal POST request, in jQuery client, so CSRF attacks will be just ignored. Switching to JSONRPC instead of normal GET/POST could solve that problem too.
  • And Bonjour. This is something I implemented last week and NOT the feature of HTTP::Engine yet, but when Remedie server launches it also publishes its hostname and port and machine name etc. over multicast DNS (aka Bonjour).
  • Will be useful for auto-discovery by clients, or share the list of channels with someone in your local networks.
  • Lots of people would have opinions which SQL database to use, for your web applications.
  • Usually you would pick one of MySQL or PostgreSQL, to build some scalable web sites with complex business logic to run against data stored on SQL server.
  • SQLite is a flat file based, portable SQL engine. It doesn’t implement all of ANSI SQL features, but very fast and useful for embedded software. There will be concurrency problems like locking if you have multiple processes opening the same SQLite database, but
  • So it’s best for desktop applications, because you’ll only have one process to open the same database, even if it’s a micro desktop web application that we’re talking about now.
  • Actually, software like Firefox, OS X’s and iCal all use SQLite as its database.
  • Another reason that it’s good for desktop apps is the end-users don’t want to and need to run SQL server processes like MySQL or postgreSQL.
  • Also, if your use SQLite as a backend for your desktop app, backing up is easy. And you can synchronize your database between two machines like Home and Work using tools like Dropbox. Very nice.
  • Let’s talk about DB schema.
  • Actually let’s NOT talk about DB schema. You probably don’t need a DBA to design Desktop application. It depends on the size of data set your app is trying to handle, but most of the time, just use as simple schema as possible, to make it flexible and easily extensible.
  • Remedie’s schema is pretty simple. It has just a few index columns, like id and names, and then column called ‘props’ where we store all the properties as a JSON encoded object, or key-value pairs.
  • Key value pair is hot.
  • There are many document database, or key-value database systems like Couch, Mongo or TokyoTyrant and they actually need servers again, like MySQL or postgres.
  • So the idea is the same: we use SQLite to store arbitrary key-value pairs with some indexes.
  • How do we abstract those Database access. We need ORM. Another fight here which ORM to use.
  • Well, you can use anything you like. I don’t have strong opinion about this right now.
  • You can use DBIC or RDBO.
  • Remedie uses RDBO right now but there’s no special reason for that. I just wanted some excuse to try something different because I always use Catalyst, Data::ObjectDriver, YUI and Template Toolkit at work and for this desktop app I wanted to try the whole new stack to build a micro web app.
  • KiokuDB is one of the hottest technologies in the Perl these days, and there were lots of talks mentioning about it in this YAPC.
  • KiokuDB can actually do with its DBI backend to save key-value JSPON data in the SQLite database. So i think Yuval and maybe Stevan are interested in porting my Remedie RDBO code over to Kioku over the next few days.
  • So for this desktop web app thing, I would’t introduce anything special from the normal jQuery usage for your web applications. Just use HTML and CSS to design the UI.
  • You better not write HTML by hand, because your app is truly dynamic. You better manipulate the DOM object and use jQuery’s Ajax method to do Ajax JSON calls to the backend.
  • There are couple of templating plugins for jQuery but I chose jQuery.flydom. which is kind of similar to Template::Declare in Perl.
  • jQuery.hotkeys is a plugin for jQuery to enable hotkeys or keyboard shortcuts, like vi-style navigation, or using arrow keys to control video playback.
  • The usage is pretty simple. It overrides the original ‘keydown’ event so that you can specify which keyboard that it listens to, and then assign a callback to the pressed key.
  • jQuery.contextMenu is a plugin to enable some right-click or control-click menu so your web application actually looks like a desktop application.
  • jQuery corners is a plugin to do round corners, pretty important for Web 2.0 sites, and for desktop applications, to implement something like this:
  • this badge-like overlay is implemented using some hover divs with rounded corners.
  • jQuery has this event system that you can bind callbacks to browser events, like mouse over, or DOM ready, or link clicked, but you can also use the event system to trigger your app specific custom events and bind callbacks to them. I heavily use this system to make my JS like a real GUI application, because with GUI application most of them are coded in Event Loops.
  • jQuery UI is an extension to jQuery that implements some UI stuff.
  • Currently, we only use jQuery UI to implement the drag & drop stuff that you saw in the demo. Maybe I could use other features of jQuery UI to do some more fancy stuff.
  • There are many other jQuery plugins that I won’t talk about today but you might be interested in, to implement some desktop-app like features.
  • That’s it for jQuery. Let’s get back to this Desktop app thing again.
  • This desktop web app sounds sexy, but it’s actually just Client-Server model, right?
  • So we have 2 “apps” basically. One is the client and the other is the server. Let’s make the client as a real application. In this case client is a browser.
  • There’re tools to make Site-Specific Browser, or SSB in short.
  • Fluid and Prism. Fluid is Safari and Prism is Firefox.
  • This is how Fluid apps would look like. They’re just another browser (Safari) process that are specific to the site, like Github or Gmail or Flickr. You can use Fluid to build a site specific browser, to your application running on localhost:9999 or whatever port.
  • The users of your desktop app will be able to customize the frontend UI using Userscripts, like Greasemonkey for Prism and GreaseKit for Fluid. Users can also skin their app using Userstyles. So you don’t need to implement those plugin mechanisms or anything like that, to allow users to customize their app. SSB can do this already.
  • Fluid also allows you to extend your app and look more like a desktop app, so your app notification can be hooked to Growl, instead of jQuery.jGrowl that I mentioned, and has an access to Dock menu, like this.
  • Remedie’s RPC is implemented as an JSON REST API, so client and server are basically decoupled. There’s no tight connection between front-end app and backend micro web server APIs.
  • So theoretically, you can have more client applications other than normal browsers like Safari or Firefox, that talk to the same backend server over API. And you have more “views” to the application.
  • For example, iPhone.
  • Finally, we can actually make the Server as an app as well.
  • by packaging the server process as a bundle.
  • I used local::lib the excellent CPAN module to have application specific library path and install all dependencies locally inside the app bundle.
  • You can also use best practical’s shipwright to do the same thing, with slightly different approach.
  • And for Mac OS X, I used a tool called Platypus, to bundle those scripts, libraries and dependent CPAN modules in a .app bundle. it runs everywhere under Leopard, no CPAN installation required.
  • Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery

    1. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::Asia 2009 Tokyo Sep. 11
    2. Interested in code? Come down to front. (fonts are small)
    3. Tatsuhiko Miyagawa
    4. Software Engineer, TypePad
    5. cpan: MIYAGAWA
    6. Acme-DateTime-Duration-Numeric Acme-Module-Authors Acme-Sneeze Acme-Sneeze-JP Apache-ACEProxy Apache- AntiSpam Apache-Clickable Apache-CustomKeywords Apache-DefaultCharset Apache-GuessCharset Apache-JavaScript- DocumentWrite Apache-No404Proxy Apache-Profiler Apache-Session-CacheAny Apache-Session-Generate-ModUniqueId Apache-Session-Generate-ModUsertrack Apache-Session-PHP Apache-Session-Serialize-YAML Apache-Singleton Apache- StickyQuery Archive-Any-Create Attribute-Profiled Attribute-Protected Attribute-Unimplemented Bundle-Sledge CGI- Untaint-email CPAN-Mini-Growl Catalyst-Plugin-Authentication-Credential-AOL Catalyst-Plugin-Authentication-Credential- OpenID Catalyst-Plugin-JSONRPC Catalyst-View-JSON Catalyst-View-Jemplate Class-DBI-AbstractSearch Class-DBI- Extension Class-DBI-Pager Class-DBI-Replication Class-DBI-SQLite Class-DBI-View Class-Trigger Convert-Base32 Convert- DUDE Convert-RACE Data-YUID Date-Japanese-Era Date-Range-Birth DateTime-Span-Birthdate Device-KeyStroke-Mobile Dunce-time Email-Find Email-Valid-Loose Encode-DoubleEncodedUTF8 Encode-First Encode-JP-Mobile Encode-JavaScript- UCS Encode-Punycode File-Find-Rule-Digest File-Spotlight Geo-Coder-Google HTML-AutoPagerize HTML-Entities- ImodePictogram HTML-RelExtor HTML-ResolveLink HTML-Selector-XPath HTML-XSSLint HTTP-MobileAgent HTTP- ProxyPAC HTTP-Server-Simple-Authen HTTP-Server-Simple-Bonjour IDNA-Punycode Inline-Basic Inline-TT JSON-Syck Kwiki-Emoticon Kwiki-Export Kwiki-Footnote Kwiki-OpenSearch Kwiki-OpenSearch-Service Kwiki-TypeKey Kwiki-URLBL LWP-UserAgent-Keychain Lingua-JA-Hepburn-Passport Log-Dispatch-Config Log-Dispatch-DBI MSIE-MenuExt Mac- Macbinary Mail-Address-MobileJp Mail-ListDetector-Detector-Fml Module-Install-Repository Net-DAAP-Server-AAC Net- IDN-Nameprep Net-IPAddr-Find Net-Twitter-OAuth Net-YahooMessenger NetAddr-IP-Find P2P-Transmission-Remote PHP-Session POE-Component-Client-AirTunes POE-Component-Client-Lingr POE-Component-YahooMessenger Path- Class-URI Plagger RPC-XML-Parser-LibXML Template-Plugin-Clickable Template-Plugin-Comma Template-Plugin-FillInForm Template-Plugin-HTML-Template Template-Plugin-JavaScript Template-Plugin-MobileAgent Template-Plugin-ResolveLink Template-Plugin-Shuffle Template-Provider-Encoding Term-Encoding Term-TtyRec Test-Synopsis Text-Emoticon Text- Emoticon-GoogleTalk Text-Emoticon-MSN Text-Emoticon-Yahoo Text-MessageFormat TheSchwartz-Simple Time-Duration- Parse Time-Duration-ja URI-Find-UTF8 URI-git URI-tag URI-urn-uuid Video-Subtitle-SRT WWW-Baseball-NPB WWW-Blog- Metadata-MobileLinkDiscovery WWW-Blog-Metadata-OpenID WWW-Blog-Metadata-OpenSearch WWW-Cache-Google WWW-Mechanize-AutoPager WWW-Mechanize-DecodedContent WWW-NicoVideo-Download WWW-OpenSearch WWW-Shorten-RevCanonical WWW-Shorten-Simple Web-Scraper Web-oEmbed WebService-Bloglines WebService- ChangesXml WebService-Google-Suggest WebService-Lingr XML-Atom XML-Atom-Lifeblog XML-Atom-Stream XML- Liberal XML-OPML-LibXML abbreviation autobox-DateTime-Duration capitalization plagger
    7. (Slides will be linked. Follow me!)
    8. Remedie
    9. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2009 Pittsburgh
    10. Desktop GUI apps
    11. MFC/.NET Visual C++,VB
    12. wxWidgets
    13. Objective-C Cocoa (PyObjC/RubyCocoa)
    14. Adobe AIR
    15. I’m a Perl guy who knows JavaScript.
    16. Web Developers!
    17. Web app!
    18. “Web 2.0 iPhone App” Steve Jobs at WWDC 2007
    19. PhoneGap
    20. HTML5 geolocation, videos local storage
    21. HTML5 = Future ??? = 2009
    22. micro Web app = 2009
    23. (Demo)
    24. New in 0.6.x
    25. Performance non-blocking, multi-tasking libxml based parsing everywhere
    26. Comet messaging parallel downloads, iPhone remotes
    27. How I built this
    28. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::Asia 2009 Tokyo Sep. 11
    29. HTTP::Engine web servers abstraction
    30. Based on Catalyst::Engine
    31. Will be replaced by PSGI and Plack
    32. But will be supported and can still be useful to write micro webservers
    33. package MyApp; sub handle_request { my $req = shift; return HTTP::Engine::Response->new( body => “Hello World”, ); } 1;
    34. Interface::PSGI Yappo++
    35. Plack compatible: CGI, ServerSimple, Mojo, Prefork ReverseHTTP, FastCGI, Apache
    36. > plackup MyApp -i ServerSimple
    37. use Plack::Loader; my $impl = PlackLoader->load(‘AnyEvent’, @ARGV); $impl->run(“MyApp”);
    38. Desktop app: AnyEvent psgi.async
    39. Serve static files (HTML/CSS/JS)
    40. sub handle_request { my($self, $req) = @_; my $path = $req->path; my $res = HTTP::Engine::Response->new; if ($path =~ s!^/static/!!) { $self->serve_static_file($path, $req, $res); }; return $res; }
    41. use Path::Class; sub serve_static_file { my($self, $path, $req, $res) = @_; my $root = $self->conf->{root}; my $file = file($root, "static", $path); my $size = -s _; my $mtime = (stat(_))[9]; my $ext = ($file =~ /.(w+)$/)[0]; $res->content_type( MIME::Types->new->mimeTypeOf($ext) || "text/plain" ); # ... open my $fh, "<:raw", $file or die "$file: $!"; $res->headers->header('Last-Modified' => HTTP::Date::time2str($mtime)); $res->headers->header('Content-Length' => $size); $res->body( join '', <$fh> ); }
    42. See Also: Plack::Middleware::Static (?)
    43. Implement Ajax backend actions (JSON-REST)
    44. sub handle_request { my($self, $req) = @_; my $path = $req->path; my $res = HTTP::Engine::Response->new; if ($path =~ s!^/rpc/!!) { $self->dispatch_rpc($path, $req, $res); } }
    45. sub dispatch_rpc { my($self, $path, $req, $res) = @_; my @class = split '/', $path; my $method = pop @class; die "Access to non-public methods" if $method =~ /^_/; my $rpc_class = $self->load_rpc_class(@class); my $rpc = $rpc_class->new( conf => $self->conf ); my $result = eval { $rpc->$method($req, $res) }; unless ( $res->body ) { $res->status(200); $res->content_type("application/json; charset=utf-8"); $res->body( Remedie::JSON->encode($result) ); } }
    46. Problem (1): Dirty API routing
    47. Path::Router, Path::Dispatcher, HTTP::Dispatcher, JSORB
    48. Problem (2): Vulnerable (CSRF)
    49. Authentication Special Headers Switch to JSONRPC
    50. Bonjour (can be Plack middleware?)
    51. Auto Discovery Share subscriptions
    52. Workers Comet messaging
    53. use Coro; use Coro::Channel; my $queue = Coro::Channel->new; sub start_workers { my($class, $numbers) = @_; for (1..$number) { async { $class->work_channel while 1 }; } } sub queue_channel { my $class = shift; my($channel_id, $conf, $opts) = @_; $queue->put([ $channel_id, $conf, $opts ]); } sub work_channel { my $class = shift; my $job = $queue->get; # blocks my($channel_id, $conf, $opts) = @$job; # update channel }
    54. use Coro; use Coro::Channel; my $queue = Coro::Channel->new; sub start_workers { my($class, $numbers) = @_; for (1..$number) { async { $class->work_channel while 1 }; } } sub queue_channel { my $class = shift; my($channel_id, $conf, $opts) = @_; $queue->put([ $channel_id, $conf, $opts ]); } sub work_channel { my $class = shift; my $job = $queue->get; # blocks my($channel_id, $conf, $opts) = @$job; # update channel }
    55. # Worker use Remedie::PubSub; sub update_channel { my($class, $channel) = @_; # update channel ... async { Remedie::PubSub->broadcast(@events) }; }
    56. package Remedie::PubSub; use Coro; use Coro::Signal; my %channels; # id => Coro::Channel sub broadcast { my($class, @events) = @_; for my $event (@events) { # who is listening? for my $queue (values %channels) { $queue->put($event); } } }
    57. # from HTTP::Engine app # /rpc/events/poll?s={clientID} sub poll { my($self, $req, $res) = @_; my $session = $req->param(‘s’); my $events = Remedie::PubSub->wait( $session, 55, # timeout ); return $events || []; }
    58. package Remedie::PubSub; sub wait { my($class, $session, $timeout) = @_; my $sweeper = async { # check timeout }; $signal->wait; my @events; push @events, $queue->get while $queue->size > 0; return @events; }
    59. See also: Stardust
    60. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::Asia 2009 Tokyo Sep. 11
    61. SQL DB choices
    62. MySQL/PostgreSQL Great for Web apps.
    63. SQLite: file-based, type-less Transactional
    64. SQLite: best for desktop apps
    65. SQLite for desktop: Firefox,, iCal
    66. End-users don’t want to run *SQL server
    67. Bonus: Easy backup, Dropbox sync
    68. DB Schema
    69. You don’t need DBA. Make it simple, flexible and extensible.
    70. Remedie schema Few indexes JSON key-values
    72. CREATE TABLE item ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, channel_id INTEGER NOT NULL, type INTEGER NOT NULL, ident TEXT NOT NULL, name TEXT NOT NULL, status INTEGER NOT NULL, props TEXT ); CREATE INDEX item_status ON item (status) CREATE UNIQUE INDEX item_ident ON item (channel_id, ident);
    73. Key-Value is HOT
    74. CouchDB, MongoDB TokyoTyrant (Need servers though)
    75. SQLite for Key-Value
    76. ORM?
    77. Anything you like.
    78. DBIx::Class Rose::DB::Object
    79. Rose::DB::Object (I wanted some excuse)
    80. See Also: KiokuDB
    81. KiokuDB DBI / SQLite backend Key-Value JSPON
    82. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2011 Tokyo Sep. 11
    83. Just use normal HTML and CSS to design UI
    84. Manipulate DOM $.ajax to do Ajax
    85. DOM Manipulation sucks.
    86. jQuery.flydom
    87. $("#channel-pane").createAppend( 'div', { className: 'channel-header', id: 'channel-header-' + }, [ 'div', { className: 'channel-header-thumb' }, [ 'img', { src: "/static/images/feed.png", alt: }, null ], ] );
    88. jQuery.hotkeys
    89. $(document).bind(‘keydown’, ‘shift+n’, function(ev){ // ‘N’ is entered });
    90. jQuery.contextMenu
    91. jQuery.corners
    92. $.event.trigger $(document).bind
    93. Integrate with Comet
    94. # /rpc/remote/command?command={javascript code} sub command { my($self, $req, $res) = @_; async { Remedie::PubSub->broadcast({ type => “command”, command => $req->param(‘command’), }); }; return { success => 1 }; }
    95. # remedie.js using jquery.ev $.ev.handlers.command = function(ev) { try { eval(ev.command) } catch(e) { alert(e) }; }; $.ev.handlers.trigger_event = function(ev) { $.event.trigger(ev.event, ev); };
    96. # iPhone HTML $.ajax({ url: “/rpc/remote/command”, type: ‘post’, data: { command: ‘remedie.showChannel(remedie.channels[‘ + + ‘])] }, success: function(r) { } });
    97. jQuery UI
    98. Fancy stuff like Drag & Drop
    99. jQuery.blockUI jQuery.scrollTo jQuery.jgrowl
    100. Building a desktop app with HTTP::Engine, SQLite & jQuery Tatsuhiko Miyagawa YAPC::NA 2011 Tokyo Sep. 11
    101. More like “Desktop app”
    102. Client-Server
    103. Web Client as “app”
    104. Site Specific Browser
    105. Fluid Prism
    106. Customize Userscripts / Userstyles
    107. Fluid hooks Growl integration Dock menu
    108. Client-Server Decoupled via APIs
    109. More Clients More “Views”
    110. iPhone
    111. 120 lines of HTML/JS using iUI project
    112. Server as “app”
    113. Packaging a server
    114. local::lib build & install all deps
    115. Also: Shipwright
    116. Platypus Make .app
    117. Download .zip, copy .app to /Applications, Run it.
    118. Also:
    119. Summary • micro web server as a desktop app • HTTP::Engine, JSONRPC and router • Coro worker and Comet • SQLite to store key-value • jQuery plugins to enable desktop UIs • More tools to make it really “.app”
    120. That’s it! Questions?
    121. Thank you!