home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 October / maximum-cd-2010-10.iso / DiscContents / vlc-1.1.0-win32.exe / lua / intf / modules / host.lua < prev   
Encoding:
Text File  |  2010-06-20  |  9.8 KB  |  314 lines

  1. --[==========================================================================[
  2.  host.lua: VLC Lua interface command line host module
  3. --[==========================================================================[
  4.  Copyright (C) 2007 the VideoLAN team
  5.  $Id$
  6.  
  7.  Authors: Antoine Cellerier <dionoea at videolan dot org>
  8.  
  9.  This program is free software; you can redistribute it and/or modify
  10.  it under the terms of the GNU General Public License as published by
  11.  the Free Software Foundation; either version 2 of the License, or
  12.  (at your option) any later version.
  13.  
  14.  This program is distributed in the hope that it will be useful,
  15.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  GNU General Public License for more details.
  18.  
  19.  You should have received a copy of the GNU General Public License
  20.  along with this program; if not, write to the Free Software
  21.  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22. --]==========================================================================]
  23.  
  24. --[==========================================================================[
  25. Example use:
  26.  
  27.     require "host"
  28.     h = host.host()
  29.  
  30.     -- Bypass any authentication
  31.     function on_password( client )
  32.         client:switch_status( host.status.read )
  33.     end
  34.     h.status_callbacks[host.status.password] = on_password
  35.  
  36.     h:listen( "localhost:4212" )
  37.     h:listen( "*console" )
  38.     --or h:listen( { "localhost:4212", "*console" } )
  39.  
  40.     -- The main loop
  41.     while not vlc.misc.should_die() do
  42.         -- accept new connections and select active clients
  43.         local write, read = h:accept_and_select()
  44.  
  45.         -- handle clients in write mode
  46.         for _, client in pairs(write) do
  47.             client:send()
  48.             client.buffer = ""
  49.             client:switch_status( host.status.read )
  50.         end
  51.  
  52.         -- handle clients in read mode
  53.         for _, client in pairs(read) do
  54.             local str = client:recv(1000)
  55.             str = string.gsub(str,"\r?\n$","")
  56.             client.buffer = "Got `"..str.."'.\r\n"
  57.             client:switch_status( host.status.write )
  58.         end
  59.     end
  60.  
  61. For complete examples see existing VLC Lua interface modules (ie telnet.lua)
  62. --]==========================================================================]
  63.  
  64. module("host",package.seeall)
  65.  
  66. status = { init = 0, read = 1, write = 2, password = 3 }
  67. client_type = { net = 1, stdio = 2, fifo = 3 }
  68.  
  69. function host()
  70.     -- private data
  71.     local clients = {}
  72.     local listeners = {}
  73.     local status_callbacks = {}
  74.  
  75.     -- private methods
  76.     local function fd_client( client )
  77.         if client.status == status.read then
  78.             return client.rfd
  79.         else -- status.write
  80.             return client.wfd
  81.         end
  82.     end
  83.  
  84.     local function send( client, data, len )
  85.         if len then
  86.             return vlc.net.send( client.wfd, data, len )
  87.         else
  88.             return vlc.net.send( client.wfd, data or client.buffer )
  89.         end
  90.     end
  91.  
  92.     local function recv( client, len )
  93.         if len then
  94.             return vlc.net.recv( client.rfd, len )
  95.         else
  96.             return vlc.net.recv( client.rfd )
  97.         end
  98.     end
  99.  
  100.     local function write( client, data )
  101.         return vlc.net.write( client.wfd, data or client.buffer )
  102.     end
  103.  
  104.     local function read( client, len )
  105.         if len then
  106.             return vlc.net.read( client.rfd, len )
  107.         else
  108.             return vlc.net.read( client.rfd )
  109.         end
  110.     end
  111.  
  112.     local function del_client( client )
  113.         if client.type == client_type.stdio then
  114.             client:send( "Cannot delete stdin/stdout client.\n" )
  115.             return
  116.         end
  117.         for i, c in pairs(clients) do
  118.             if c == client then
  119.                 if client.type == client_type.net then
  120.                     if client.wfd ~= client.rfd then
  121.                         vlc.net.close( client.rfd )
  122.                     end
  123.                     vlc.net.close( client.wfd )
  124.                 end
  125.                 clients[i] = nil
  126.                 return
  127.             end
  128.         end
  129.         vlc.msg.err("couldn't find client to remove.")
  130.     end
  131.     
  132.     local function switch_status( client, s )
  133.         if client.status == s then return end
  134.         client.status = s
  135.         if status_callbacks[s] then
  136.             status_callbacks[s]( client )
  137.         end
  138.     end
  139.  
  140.     -- append a line to a client's (output) buffer
  141.     local function append( client, string )
  142.         client.buffer = client.buffer .. string .. "\r\n"
  143.     end
  144.  
  145.     local function new_client( h, fd, wfd, t )
  146.         if fd < 0 then return end
  147.         local w, r
  148.         if t == client_type.net then
  149.             w = send
  150.             r = recv
  151.         else if t == client_type.stdio or t == client_type.fifo then
  152.             w = write
  153.             r = read
  154.         else
  155.             error("Unknown client type", t )
  156.         end end
  157.         local client = { -- data
  158.                          rfd = fd,
  159.                          wfd = wfd or fd,
  160.                          status = status.init,
  161.                          buffer = "",
  162.                          type = t,
  163.                          -- methods
  164.                          fd = fd_client,
  165.                          send = w,
  166.                          recv = r,
  167.                          del = del_client,
  168.                          switch_status = switch_status,
  169.                          append = append,
  170.                        }
  171.         client:send( "VLC media player "..vlc.misc.version().."\n" )
  172.         table.insert(clients, client)
  173.         client:switch_status(status.password)
  174.     end
  175.  
  176.     -- public methods
  177.     local function _listen_tcp( h, host, port )
  178.         if listeners.tcp and listeners.tcp[host]
  179.                          and listeners.tcp[host][port] then
  180.             error("Already listening on tcp host `"..host..":"..tostring(port).."'")
  181.         end
  182.         if not listeners.tcp then
  183.             listeners.tcp = {}
  184.         end
  185.         if not listeners.tcp[host] then
  186.             listeners.tcp[host] = {}
  187.         end
  188.         local listener = vlc.net.listen_tcp( host, port )
  189.         listeners.tcp[host][port] = listener
  190.         if not listeners.tcp.list then
  191.             -- FIXME: if host == "list" we'll have a problem
  192.             listeners.tcp.list = {}
  193.             local m = { __mode = "v" } -- week values
  194.             setmetatable( listeners.tcp.list, m )
  195.         end
  196.         table.insert( listeners.tcp.list, listener )
  197.     end
  198.  
  199.     local function _listen_stdio( h )
  200.         
  201.         if listeners.stdio then
  202.             error("Already listening on stdio")
  203.         end
  204.         new_client( h, 0, 1, client_type.stdio )
  205.         listeners.stdio = true
  206.     end
  207.  
  208.     local function _listen( h, url )
  209.         if type(url)==type({}) then
  210.             for _,u in pairs(url) do
  211.                 h:listen( u )
  212.             end
  213.         else
  214.             vlc.msg.info( "Listening on host \""..url.."\"." )
  215.             if url == "*console" then
  216.                 h:listen_stdio()
  217.             else
  218.                 u = vlc.net.url_parse( url )
  219.                 h:listen_tcp( u.host, u.port )
  220.             end
  221.         end
  222.     end
  223.  
  224.     local function _accept_and_select( h, timeout )
  225.         local function filter_client( fds, status, event )
  226.             for _, client in pairs(clients) do
  227.                 if client.status == status then
  228.                     fds[client:fd()] = event
  229.                 end
  230.             end
  231.         end
  232.  
  233.         local pollfds = {}
  234.         filter_client( pollfds, status.read, vlc.net.POLLIN )
  235.         filter_client( pollfds, status.password, vlc.net.POLLIN )
  236.         filter_client( pollfds, status.write, vlc.net.POLLOUT )
  237.         if listeners.tcp then
  238.             for _, listener in pairs(listeners.tcp.list) do
  239.                 for _, fd in pairs({listener:fds()}) do
  240.                     pollfds[fd] = vlc.net.POLLIN
  241.                 end
  242.             end
  243.         end
  244.  
  245.         local ret = vlc.net.poll( pollfds, timeout or -1 )
  246.         local wclients = {}
  247.         local rclients = {}
  248.         if ret > 0 then
  249.             for _, client in pairs(clients) do
  250.                 if pollfds[client:fd()] == vlc.net.POLLOUT then
  251.                     table.insert(wclients,client)
  252.                 end
  253.                 if pollfds[client:fd()] == vlc.net.POLLIN then
  254.                     table.insert(rclients,client)
  255.                 end
  256.             end
  257.             if listeners.tcp then
  258.                 for _, listener in pairs(listeners.tcp.list) do
  259.                     for _, fd in pairs({listener:fds()}) do
  260.                         if pollfds[fd] == vlc.net.POLLIN then
  261.                             local afd = listener:accept()
  262.                             new_client( h, afd, afd, client_type.net )
  263.                             break
  264.                         end
  265.                     end
  266.                 end
  267.             end
  268.         end
  269.  
  270.         return wclients, rclients
  271.     end
  272.  
  273.     local function destructor( h )
  274.         print "destructor"
  275.         for _,client in pairs(clients) do
  276.             client:send("Shutting down.")
  277.             if client.type == client_type.tcp then
  278.                 if client.wfd ~= client.rfd then
  279.                     vlc.net.close(client.rfd)
  280.                 end
  281.                 vlc.net.close(client.wfd)
  282.             end
  283.         end
  284.     end
  285.  
  286.     local function _broadcast( h, msg )
  287.         for _,client in pairs(clients) do
  288.             client:send( msg )
  289.         end
  290.     end
  291.  
  292.     -- the instance
  293.     local h = { -- data
  294.                 status_callbacks = status_callbacks,
  295.                 -- methods
  296.                 listen = _listen,
  297.                 listen_tcp = _listen_tcp,
  298.                 listen_stdio = _listen_stdio,
  299.                 accept_and_select = _accept_and_select,
  300.                 broadcast = _broadcast,
  301.               }
  302.  
  303.     -- the metatable
  304.     local m = { -- data
  305.                 __metatable = "Nothing to see here. Move along.",
  306.                 -- methods
  307.                 __gc = destructor,
  308.               }
  309.  
  310.     setmetatable( h, m )
  311.  
  312.     return h
  313. end
  314.