Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

24,823 views

Published on

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

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. twitter.com/miyagawa (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, Mail.app, 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
  71. CREATE TABLE channel ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, type INTEGER NOT NULL, parent INTEGER NOT NULL, ident TEXT NOT NULL, name TEXT NOT NULL, props TEXT ); CREATE UNIQUE INDEX channel_ident ON channel (ident);
  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-' + channel.id }, [ 'div', { className: 'channel-header-thumb' }, [ 'img', { src: "/static/images/feed.png", alt: channel.name }, 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[‘ + channel.id + ‘])] }, 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: github.com/miyagawa/perl-app-builder
  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! twitter.com/miyagawa

×