home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / vlc-1.1.10-win32.exe / lua / intf / modules / host.lua < prev   
Encoding:
Text File  |  2011-06-05  |  10.2 KB  |  322 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 is_flag_set(val, flag)
  70.     return (((val - (val % flag)) / flag) % 2 ~= 0)
  71. end
  72.  
  73. function host()
  74.     -- private data
  75.     local clients = {}
  76.     local listeners = {}
  77.     local status_callbacks = {}
  78.  
  79.     -- private methods
  80.     local function fd_client( client )
  81.         if client.status == status.read then
  82.             return client.rfd
  83.         else -- status.write
  84.             return client.wfd
  85.         end
  86.     end
  87.  
  88.     local function send( client, data, len )
  89.         if len then
  90.             return vlc.net.send( client.wfd, data, len )
  91.         else
  92.             return vlc.net.send( client.wfd, data or client.buffer )
  93.         end
  94.     end
  95.  
  96.     local function recv( client, len )
  97.         if len then
  98.             return vlc.net.recv( client.rfd, len )
  99.         else
  100.             return vlc.net.recv( client.rfd )
  101.         end
  102.     end
  103.  
  104.     local function write( client, data )
  105.         return vlc.net.write( client.wfd, data or client.buffer )
  106.     end
  107.  
  108.     local function read( client, len )
  109.         if len then
  110.             return vlc.net.read( client.rfd, len )
  111.         else
  112.             return vlc.net.read( client.rfd )
  113.         end
  114.     end
  115.  
  116.     local function del_client( client )
  117.         if client.type == client_type.stdio then
  118.             client:send( "Cannot delete stdin/stdout client.\n" )
  119.             return
  120.         end
  121.         for i, c in pairs(clients) do
  122.             if c == client then
  123.                 if client.type == client_type.net then
  124.                     if client.wfd ~= client.rfd then
  125.                         vlc.net.close( client.rfd )
  126.                     end
  127.                     vlc.net.close( client.wfd )
  128.                 end
  129.                 clients[i] = nil
  130.                 return
  131.             end
  132.         end
  133.         vlc.msg.err("couldn't find client to remove.")
  134.     end
  135.     
  136.     local function switch_status( client, s )
  137.         if client.status == s then return end
  138.         client.status = s
  139.         if status_callbacks[s] then
  140.             status_callbacks[s]( client )
  141.         end
  142.     end
  143.  
  144.     -- append a line to a client's (output) buffer
  145.     local function append( client, string )
  146.         client.buffer = client.buffer .. string .. "\r\n"
  147.     end
  148.  
  149.     local function new_client( h, fd, wfd, t )
  150.         if fd < 0 then return end
  151.         local w, r
  152.         if t == client_type.net then
  153.             w = send
  154.             r = recv
  155.         else if t == client_type.stdio or t == client_type.fifo then
  156.             w = write
  157.             r = read
  158.         else
  159.             error("Unknown client type", t )
  160.         end end
  161.         local client = { -- data
  162.                          rfd = fd,
  163.                          wfd = wfd or fd,
  164.                          status = status.init,
  165.                          buffer = "",
  166.                          cmds = "",
  167.                          type = t,
  168.                          -- methods
  169.                          fd = fd_client,
  170.                          send = w,
  171.                          recv = r,
  172.                          del = del_client,
  173.                          switch_status = switch_status,
  174.                          append = append,
  175.                        }
  176.         client:send( "VLC media player "..vlc.misc.version().."\n" )
  177.         table.insert(clients, client)
  178.         client:switch_status(status.password)
  179.     end
  180.  
  181.     -- public methods
  182.     local function _listen_tcp( h, host, port )
  183.         if listeners.tcp and listeners.tcp[host]
  184.                          and listeners.tcp[host][port] then
  185.             error("Already listening on tcp host `"..host..":"..tostring(port).."'")
  186.         end
  187.         if not listeners.tcp then
  188.             listeners.tcp = {}
  189.         end
  190.         if not listeners.tcp[host] then
  191.             listeners.tcp[host] = {}
  192.         end
  193.         local listener = vlc.net.listen_tcp( host, port )
  194.         listeners.tcp[host][port] = listener
  195.         if not listeners.tcp.list then
  196.             -- FIXME: if host == "list" we'll have a problem
  197.             listeners.tcp.list = {}
  198.             local m = { __mode = "v" } -- week values
  199.             setmetatable( listeners.tcp.list, m )
  200.         end
  201.         table.insert( listeners.tcp.list, listener )
  202.     end
  203.  
  204.     local function _listen_stdio( h )
  205.         
  206.         if listeners.stdio then
  207.             error("Already listening on stdio")
  208.         end
  209.         new_client( h, 0, 1, client_type.stdio )
  210.         listeners.stdio = true
  211.     end
  212.  
  213.     local function _listen( h, url )
  214.         if type(url)==type({}) then
  215.             for _,u in pairs(url) do
  216.                 h:listen( u )
  217.             end
  218.         else
  219.             vlc.msg.info( "Listening on host \""..url.."\"." )
  220.             if url == "*console" then
  221.                 h:listen_stdio()
  222.             else
  223.                 u = vlc.net.url_parse( url )
  224.                 h:listen_tcp( u.host, u.port )
  225.             end
  226.         end
  227.     end
  228.  
  229.     local function _accept_and_select( h, timeout )
  230.         local function filter_client( fds, status, event )
  231.             for _, client in pairs(clients) do
  232.                 if client.status == status then
  233.                     fds[client:fd()] = event
  234.                 end
  235.             end
  236.         end
  237.  
  238.         local pollfds = {}
  239.         filter_client( pollfds, status.read, vlc.net.POLLIN )
  240.         filter_client( pollfds, status.password, vlc.net.POLLIN )
  241.         filter_client( pollfds, status.write, vlc.net.POLLOUT )
  242.         if listeners.tcp then
  243.             for _, listener in pairs(listeners.tcp.list) do
  244.                 for _, fd in pairs({listener:fds()}) do
  245.                     pollfds[fd] = vlc.net.POLLIN
  246.                 end
  247.             end
  248.         end
  249.  
  250.         local ret = vlc.net.poll( pollfds )
  251.         local wclients = {}
  252.         local rclients = {}
  253.         if ret > 0 then
  254.             for _, client in pairs(clients) do
  255.                 if is_flag_set(pollfds[client:fd()], vlc.net.POLLERR)
  256.                 or is_flag_set(pollfds[client:fd()], vlc.net.POLLHUP)
  257.                 or is_flag_set(pollfds[client:fd()], vlc.net.POLLNVAL) then
  258.                     del_client(client)
  259.                 elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLOUT) then
  260.                     table.insert(wclients,client)
  261.                 elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLIN) then
  262.                     table.insert(rclients,client)
  263.                 end
  264.             end
  265.             if listeners.tcp then
  266.                 for _, listener in pairs(listeners.tcp.list) do
  267.                     for _, fd in pairs({listener:fds()}) do
  268.                         if is_flag_set(pollfds[fd], vlc.net.POLLIN) then
  269.                             local afd = listener:accept()
  270.                             new_client( h, afd, afd, client_type.net )
  271.                             break
  272.                         end
  273.                     end
  274.                 end
  275.             end
  276.         end
  277.  
  278.         return wclients, rclients
  279.     end
  280.  
  281.     local function destructor( h )
  282.         print "destructor"
  283.         for _,client in pairs(clients) do
  284.             client:send("Shutting down.")
  285.             if client.type == client_type.tcp then
  286.                 if client.wfd ~= client.rfd then
  287.                     vlc.net.close(client.rfd)
  288.                 end
  289.                 vlc.net.close(client.wfd)
  290.             end
  291.         end
  292.     end
  293.  
  294.     local function _broadcast( h, msg )
  295.         for _,client in pairs(clients) do
  296.             client:send( msg )
  297.         end
  298.     end
  299.  
  300.     -- the instance
  301.     local h = { -- data
  302.                 status_callbacks = status_callbacks,
  303.                 -- methods
  304.                 listen = _listen,
  305.                 listen_tcp = _listen_tcp,
  306.                 listen_stdio = _listen_stdio,
  307.                 accept_and_select = _accept_and_select,
  308.                 broadcast = _broadcast,
  309.               }
  310.  
  311.     -- the metatable
  312.     local m = { -- data
  313.                 __metatable = "Nothing to see here. Move along.",
  314.                 -- methods
  315.                 __gc = destructor,
  316.               }
  317.  
  318.     setmetatable( h, m )
  319.  
  320.     return h
  321. end
  322.