## RSence # Copyright 2008 Riassence Inc. # http://riassence.com/ # # You should have received a copy of the GNU General Public License along # with this software package. If not, contact licensing@riassence.com ## require 'rubygems' begin require 'RMagick' rescue LoadError warn "Warning: RMagick not installed, ticketserve images will not be supported." if RSence.args[:verbose] end require 'randgen' # the library path of this plugin lib_path = File.join( bundle_path, 'lib' ) # common functionality require File.join(lib_path,'common') # rsrc-related functionality require File.join(lib_path,'rsrc') # file-related functionality require File.join(lib_path,'file') # upload-related functionality require File.join(lib_path,'upload') # img-related functionality require File.join(lib_path,'img') # favicon-related functionality require File.join(lib_path,'favicon') # smart object wrapper require File.join(lib_path,'objblob') # TicketPlugin serves static and disposable data and images. It accepts Magick::Image objects too to render them only when really needed. Each serve-call returns an unique uri to pass to the client. # It performs clean-ups based on session and request time-outs. # # It's available to other plugins as +@plugins.ticket+ class TicketPlugin < Plugin # @private No user-addressable code inside class TicketServe include TicketService::Common include TicketService::Rsrc include TicketService::TicketFile include TicketService::Upload include TicketService::Img include TicketService::Favicon include TicketService::ObjBlob end # @private Returns the broker's url's. Used in {#match} def broker_urls ::RSence.config[:broker_urls] end # @private Implements this part of the {RSence::Plugins::Servlet__ Servlet} API on a plugin to match the {#broker_urls} def match( uri, request_type ) if request_type == :post upload_match = uri.start_with?( broker_urls[:u] + '/') return true if upload_match elsif request_type == :get if uri.match( /^#{broker_urls[:i]}/ ) return true elsif uri.match( /^#{broker_urls[:d]}/ ) return true elsif uri.match( /^#{broker_urls[:f]}/ ) return true elsif uri.match( /^#{broker_urls[:b]}/ ) return true elsif uri == broker_urls[:favicon] return true elsif uri == broker_urls[:uploader_iframe] return true end end return false end # @private Override with a lower score, if you want to match some parts in alternative ways. def score; 200; end # @private Implements this part of the {RSence::Plugins::Servlet__ Servlet} API on a plugin to respond to get requests matched by the {#match} def get( req, res, ses ) uri = req.fullpath if uri.match( /^#{broker_urls[:i]}/ ) puts "/i: #{uri.inspect}" if RSence.args[:verbose] @ticketserve.get_ticket( req, res, :img ) elsif uri.match( /^#{broker_urls[:d]}/ ) puts "/d: #{uri.inspect}" if RSence.args[:verbose] @ticketserve.get_ticket( req, res, :rsrc ) elsif uri.match( /^#{broker_urls[:f]}/ ) puts "/f: #{uri.inspect}" if RSence.args[:verbose] @ticketserve.get_ticket( req, res, :file ) elsif uri.match( /^#{broker_urls[:b]}/ ) puts "/b: #{uri.inspect}" if RSence.args[:verbose] @ticketserve.get_ticket( req, res, :blobobj ) elsif uri == broker_urls[:favicon] @ticketserve.favicon( req, res ) elsif uri == broker_urls[:uploader_iframe] puts "/U/iframe_html: #{uri.inspect}" if RSence.args[:verbose] res.status = 200 http_body = 'Empty Iframe for Uploading' res['content-type'] = 'text/html; charset=UTF-8' res['content-length'] = http_body.size.to_s res.body = http_body end end # @private Handles the upload request def post( req, res, ses ) uri = req.fullpath if uri.start_with?( broker_urls[:u] + '/') puts "/U: #{uri.inspect}" if RSence.args[:verbose] @ticketserve.upload( req, res ) end end # @private Initializes storage. def init # :nodoc: super @ticketserve = TicketServe.new end # @private Shuts down TicketServe def shutdown @ticketserve.shutdown end # API for BlobObj's class BlobObj # @param [String] data The data to serve # @param [String] mime The content-type of the data to serve def initialize(data,mime) @data = data @mime = mime end # @return [String] The content-type served def mime return @mime end # @return [String] The data served def data return @data end # @return [Number] The size (in bytes) of the data def size return @data.size end # Implement, if you need to do cleanup before destructing def close end end # Serves an RMagick::Image object accessible by a disposable ticket URL. # # @param [Message] msg The message instance. # @param [#to_blob] content Image data to serve # @param [String] format To pass on as a +{ self.format = format }+ block of +content#to_blob+ # @param [Symbol] type The type of the object. # # @return [String] Disposable URL. Destroyed after being requested. def serve( msg, content, format='PNG', type=:img ) @ticketserve.serve( msg, content, format, type ) end # @private Removes data used by the session, takes session id def expire_ses_id( ses_id ) @ticketserve.expire_ses( ses_id ) end # @private Removes data used by the session, takes msg def expire_ses( msg ) expire_ses_id( msg.ses_id ) end # Sets a custom favicon for RSence # # @param [String] ico_data Favicon-compatible image data in binary. # @param [String] content_type The content-type of the favicon image data. # # @return [nil] def set_favicon( ico_data, content_type=false ) @ticketserve.set_favicon( ico_data, content_type ) end # Removes a downloadable file resource served from memory. # # Does not delete any files from the file system. # # @param [Message] msg The message instance. # @param [String] file_id The file url returned by {#serve_file} # # @return [nil] def del_file( msg, file_id ) @ticketserve.del_file( file_id, msg.ses_id ) end # Serves a downloadable file resource to be served from memory using a generated url. # # @param [Message] msg The message instance. # @param [String] content The file attachment file data in binary. # @param [String] content_type The content-type of the file attachment. # @param [String] filename The filename of the download (not the url) # # @return [String] Disposable URL. Destroyed after being requested. def serve_file( msg, content='', content_type='text/plain', filename='' ) @ticketserve.serve_file( msg, content, content_type, filename ) end # Removes a downloadable file resource served from memory. # # Does not delete any files from the file system. # # @param [Message] msg The message instance. # @param [String] img_id The image url returned by {#serve_img} # # @return [nil] def del_img( msg, img_id ) @ticketserve.del_img( img_id, msg.ses_id ) end # Serves a downloadable file resource to be served from memory using a generated url. # # @param [Message] msg The message instance. # @param [#to_blob] content Image data to serve # @param [String] format To pass on as a +{ self.format = format }+ block of +content#to_blob+ # @param [Symbol] type The type of the object. # # @return [String] Disposable URL. Destroyed after being requested. def serve_img( msg, content, format='PNG', type=:img ) @ticketserve.serve_img( msg, content, format, type ) end # @return [BlobObj] to be used for custom objects served by {#serve_obj} def proto_obj return BlobObj end # Serves custom object using the {BlobObj} API (Binary Large Object) # # @param [Message] msg The message instance. # @param [BlobObj] blob_obj The custom object to serve. # @param [Boolean] no_expire When true, keeps in memory until {#del_obj} is called manually. # # @return [String] URL. Destroyed after being requested, unless +no_expire+ is +true+. def serve_obj( msg, blob_obj, no_expire=false ) @ticketserve.serve_blobobj( msg, blob_obj, no_expire ) end # Deletes a custom object served by {#serve_obj} # # @param [Message] msg The message instance. # @param [String] ticket_id The object url returned by {#serve_img} # # @return [nil] def del_obj( msg, ticket_id ) @ticketserve.del_blobobj( ticket_id, msg.ses_id ) end # Removes static resource served by {#serve_rsrc} # # @param [String] rsrc_id The object url returned by {#serve_rsrc} # # @return [nil] def del_rsrc( rsrc_id ) @ticketserve.del_rsrc( rsrc_id ) end # Serves static resource as from raw binary data. # # @param [String] content Any binary data to serve # @param [String] content_type The content-type to serve the +content+ as. # # @return [String] A static url. Use {#del_rsrc} manually to free the memory occupied by the content. def serve_rsrc( content, content_type ) @ticketserve.serve_rsrc( content, content_type ) end # Returns a list of uploads matching the ticket id. # # @param [String] ticket_id The key for the upload, returned by {#upload_key} # @param [Boolean] with_data Return data also # # @return [Array] List of uploaded data matching the ticket_id def get_uploads( ticket_id, with_data=false ) @ticketserve.get_uploads( ticket_id, with_data ) end # Removes the uploaded data matching both ticket id as well as row id. # # @param [String] ticket_id The key for the upload, returned by {#upload_key} # @param [Number] row_id The row id returned by {#get_uploads} # # @return [nil] def del_upload( ticket_id, row_id ) @ticketserve.del_upload( ticket_id, row_id ) end # Removes all uploaded data matching the ticket id # # @param [Message] msg The message instance. # @param [String] ticket_id The key for the upload, returned by {#upload_key} # # @return [nil] def del_uploads( msg, ticket_id ) @ticketserve.del_uploads( ticket_id, msg.ses_id ) end # Allocates an upload slot and returns the ticket id to use for {#get_uploads}, {#del_upload} and {#del_uploads} # # @param [Message] msg The message instance. # @param [String] value_key The key for the value associated with the upload. See {RSence::HValue#value_id} # @param [Number] max_size The maximum size allowed to upload. # @param [RegExp] mime_allow A regular expression to match what types of data are allowed to be uploaded # @param [Boolean] allow_multi When false, allows uploading only once per key. # # @return [String] The ticket id. Use for the {RSence::HValue HValue} used with the client HUploader component. Also use with {#get_uploads}, {#del_upload} and {#del_uploads} def upload_key( msg, value_key, max_size=1000000, mime_allow=/(.*?)\/(.*?)/, allow_multi=true ) @ticketserve.upload_key( msg, value_key, max_size, mime_allow, allow_multi ) end end