1 /*****************************************************************************
2 * services_discovery.c : Services discovery using lua scripts
3 *****************************************************************************
4 * Copyright (C) 2009 VideoLAN and AUTHORS
6 * Authors: Fabio Ritrovato <sephiroth87 at videolan dot org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
27 #include <vlc_common.h>
28 #include <vlc_services_discovery.h>
33 /*****************************************************************************
35 *****************************************************************************/
36 static void *Run( void * );
37 static int DoSearch( services_discovery_t
*p_sd
, const char *psz_query
);
38 static int Search( services_discovery_t
*p_sd
, const char *psz_query
);
40 static const char * const ppsz_sd_options
[] = { "sd", "longname", NULL
};
42 /*****************************************************************************
44 *****************************************************************************/
45 struct services_discovery_sys_t
58 static const luaL_Reg p_reg
[] = { { NULL
, NULL
} };
60 /*****************************************************************************
61 * Open: initialize and create stuff
62 *****************************************************************************/
63 int Open_LuaSD( vlc_object_t
*p_this
)
65 services_discovery_t
*p_sd
= ( services_discovery_t
* )p_this
;
66 services_discovery_sys_t
*p_sys
;
70 if( !strcmp(p_sd
->psz_name
, "lua"))
72 // We want to load the module name "lua"
73 // This module can be used to load lua script not registered
74 // as builtin lua SD modules.
75 config_ChainParse( p_sd
, "lua-", ppsz_sd_options
, p_sd
->p_cfg
);
76 psz_name
= var_CreateGetString( p_sd
, "lua-sd" );
80 // We are loading a builtin lua sd module.
81 psz_name
= strdup(p_sd
->psz_name
);
84 if( !( p_sys
= malloc( sizeof( services_discovery_sys_t
) ) ) )
90 p_sd
->pf_search
= Search
;
91 p_sys
->psz_filename
= vlclua_find_file( p_this
, "sd", psz_name
);
92 if( !p_sys
->psz_filename
)
94 msg_Err( p_sd
, "Couldn't find lua services discovery script \"%s\".",
103 msg_Err( p_sd
, "Could not create new Lua State" );
106 vlclua_set_this( L
, p_sd
);
108 luaL_register( L
, "vlc", p_reg
);
115 luaopen_strings( L
);
116 luaopen_variables( L
);
118 luaopen_gettext( L
);
123 if( vlclua_add_modules_path( p_sd
, L
, p_sys
->psz_filename
) )
125 msg_Warn( p_sd
, "Error while setting the module search path for %s",
126 p_sys
->psz_filename
);
129 if( luaL_dofile( L
, p_sys
->psz_filename
) )
131 msg_Err( p_sd
, "Error loading script %s: %s", p_sys
->psz_filename
,
132 lua_tostring( L
, lua_gettop( L
) ) );
137 vlc_mutex_init( &p_sys
->lock
);
138 vlc_cond_init( &p_sys
->cond
);
139 p_sys
->b_exiting
= false;
140 TAB_INIT( p_sys
->i_query
, p_sys
->ppsz_query
);
142 if( vlc_clone (&p_sd
->p_sys
->thread
, Run
, p_sd
, VLC_THREAD_PRIORITY_LOW
) )
144 TAB_CLEAN( p_sys
->i_query
, p_sys
->ppsz_query
);
145 vlc_cond_destroy( &p_sys
->cond
);
146 vlc_mutex_destroy( &p_sys
->lock
);
154 free( p_sys
->psz_filename
);
159 /*****************************************************************************
161 *****************************************************************************/
162 void Close_LuaSD( vlc_object_t
*p_this
)
164 services_discovery_t
*p_sd
= ( services_discovery_t
* )p_this
;
166 vlc_mutex_lock( &p_sd
->p_sys
->lock
);
167 p_sd
->p_sys
->b_exiting
= true;
168 vlc_mutex_unlock( &p_sd
->p_sys
->lock
);
170 vlc_cancel( p_sd
->p_sys
->thread
);
171 vlc_join (p_sd
->p_sys
->thread
, NULL
);
173 for( int i
= 0; i
< p_sd
->p_sys
->i_query
; i
++ )
174 free( p_sd
->p_sys
->ppsz_query
[i
] );
175 TAB_CLEAN( p_sd
->p_sys
->i_query
, p_sd
->p_sys
->ppsz_query
);
177 vlc_cond_destroy( &p_sd
->p_sys
->cond
);
178 vlc_mutex_destroy( &p_sd
->p_sys
->lock
);
179 free( p_sd
->p_sys
->psz_filename
);
180 lua_close( p_sd
->p_sys
->L
);
184 /*****************************************************************************
185 * Run: Thread entry-point
186 ****************************************************************************/
187 static void* Run( void *data
)
189 services_discovery_t
*p_sd
= ( services_discovery_t
* )data
;
190 services_discovery_sys_t
*p_sys
= p_sd
->p_sys
;
191 lua_State
*L
= p_sys
->L
;
193 int cancel
= vlc_savecancel();
195 lua_getglobal( L
, "main" );
196 if( !lua_isfunction( L
, lua_gettop( L
) ) || lua_pcall( L
, 0, 1, 0 ) )
198 msg_Err( p_sd
, "Error while running script %s, "
199 "function main(): %s", p_sys
->psz_filename
,
200 lua_tostring( L
, lua_gettop( L
) ) );
202 vlc_restorecancel( cancel
);
205 msg_Dbg( p_sd
, "LuaSD script loaded: %s", p_sys
->psz_filename
);
207 /* Force garbage collection, because the core will keep the SD
208 * open, but lua will never gc until lua_close(). */
209 lua_gc( L
, LUA_GCCOLLECT
, 0 );
211 vlc_restorecancel( cancel
);
213 /* Main loop to handle search requests */
214 vlc_mutex_lock( &p_sys
->lock
);
215 mutex_cleanup_push( &p_sys
->lock
);
216 while( !p_sys
->b_exiting
)
218 /* Wait for a request */
219 while( !p_sys
->i_query
)
220 vlc_cond_wait( &p_sys
->cond
, &p_sys
->lock
);
222 /* Execute every query each one protected against cancelation */
223 cancel
= vlc_savecancel();
224 while( !p_sys
->b_exiting
&& p_sys
->i_query
)
226 char *psz_query
= p_sys
->ppsz_query
[p_sys
->i_query
- 1];
227 REMOVE_ELEM( p_sys
->ppsz_query
, p_sys
->i_query
, p_sys
->i_query
- 1 );
229 vlc_mutex_unlock( &p_sys
->lock
);
230 DoSearch( p_sd
, psz_query
);
232 vlc_mutex_lock( &p_sys
->lock
);
234 vlc_restorecancel( cancel
);
241 /*****************************************************************************
242 * Search: search for items according to the given query
243 ****************************************************************************/
244 static int Search( services_discovery_t
*p_sd
, const char *psz_query
)
246 services_discovery_sys_t
*p_sys
= p_sd
->p_sys
;
247 vlc_mutex_lock( &p_sys
->lock
);
248 TAB_APPEND( p_sys
->i_query
, p_sys
->ppsz_query
, strdup( psz_query
) );
249 vlc_cond_signal( &p_sys
->cond
);
250 vlc_mutex_unlock( &p_sys
->lock
);
255 static int DoSearch( services_discovery_t
*p_sd
, const char *psz_query
)
257 services_discovery_sys_t
*p_sys
= p_sd
->p_sys
;
258 lua_State
*L
= p_sys
->L
;
260 /* Lookup for the 'search' function */
261 lua_getglobal( L
, "search" );
262 if( !lua_isfunction( L
, lua_gettop( L
) ) )
264 msg_Err( p_sd
, "The script '%s' does not define any 'search' function",
265 p_sys
->psz_filename
);
271 lua_pushstring( L
, psz_query
);
273 /* Call the 'search' function */
274 if( lua_pcall( L
, 1, 0, 0 ) )
276 msg_Err( p_sd
, "Error while running the script '%s': %s",
277 p_sys
->psz_filename
, lua_tostring( L
, lua_gettop( L
) ) );