Feature request: suggestion for cPlugin

Message ID 4307D550.8000205@gmx.de
State New
Headers

Commit Message

Udo Richter Aug. 21, 2005, 1:13 a.m. UTC
  Udo Richter wrote:
> New patch including docs etc. later this day.

... as promised. Custom plugin services, including PLUGINS.html and
newplugin update. This version still mentions Data=NULL as supported query.

Cheers,

Udo
  

Comments

Klaus Schmidinger Aug. 21, 2005, 9:51 a.m. UTC | #1
Udo Richter wrote:
> Udo Richter wrote:
> 
>>New patch including docs etc. later this day.
> 
> 
> ... as promised. Custom plugin services, including PLUGINS.html and
> newplugin update. This version still mentions Data=NULL as supported query.
> ...
> +To send messages to, or request services from some plugin that offers the protocol, the 
> +plugin can call the function <tt>cPluginManager::CallFirstService</tt>. This function
> +will send the request to the first plugin that supports this service protocol. The 

Actually it sends the call to _every_ plugin and returns as soon as one
has processed it. Should this be rephrased, or should the implementation
be changed to

cPlugin *cPluginManager::CallFirstService(const char *Id, void *Data)
{
   if (pluginManager) {
      for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) {
          cPlugin *p = dll->Plugin();
          if (p && p->Service(Id, NULL) && p->Service(Id, Data))
             return p;
          }
      }
   return NULL;
}

> +function returns a pointer to the plugin that handled the request, or <tt>NULL</tt>
> +if no plugin handles the request.
> +<p>
> +To send a messages to all plugins, the plugin can call the function 
> +<tt>cPluginManager::CallAllServices</tt>. This function will send the request to 
> +all plugins that support this service protocol.

Actually it sends the request to _all_ plugins, because it doesn't explicitly
check whether a particular plugin supports it. In this case this doesn't make
much difference, but I think the description should reflect what actually happens.

Klaus
  
Udo Richter Aug. 21, 2005, 12:45 p.m. UTC | #2
Klaus Schmidinger wrote:
> Actually it sends the call to _every_ plugin and returns as soon as one
> has processed it. Should this be rephrased, or should the implementation
> be changed to
> 
>          if (p && p->Service(Id, NULL) && p->Service(Id, Data))
>             return p;

I would prefer to not call the function twice, to avoid the redundant
string compare.

----8<----
To send messages to, or request services from some plugin that offers
the protocol, the plugin can call the function
<tt>cPluginManager::CallFirstService</tt>. This function will send the
request to all plugins until one plugin handles the service call. The
function returns a pointer to the plugin that handled the call, or
<tt>NULL</tt> if no plugin handled the call.
<p>
To send a messages to all plugins, the plugin can call the function
<tt>cPluginManager::CallAllServices</tt>. The function returns
<tt>true</tt> if any plugin handled the service call, or <tt>false</tt>
if no plugin handled the call.
----8<----

Cheers,

Udo
  

Patch

diff -au vdr-1.3.29-orig/newplugin vdr-1.3.29/newplugin
--- vdr-1.3.29-orig/newplugin	2005-01-30 14:50:05.000000000 +0100
+++ vdr-1.3.29/newplugin	2005-08-20 19:45:04.000000000 +0200
@@ -170,6 +170,7 @@ 
   virtual cOsdObject *MainMenuAction(void);
   virtual cMenuSetupPage *SetupMenu(void);
   virtual bool SetupParse(const char *Name, const char *Value);
+  virtual bool Service(const char *Id, void *Data = NULL);
   };
 
 cPlugin${PLUGIN_CLASS}::cPlugin$PLUGIN_CLASS(void)
@@ -236,6 +237,12 @@ 
   return false;
 }
 
+bool cPlugin${PLUGIN_CLASS}::Service(const char *Id, void *Data)
+{
+  // Handle custom service requests from other plugins
+  return false;
+}
+
 VDRPLUGINCREATOR(cPlugin$PLUGIN_CLASS); // Don't touch this!
 };
 
diff -au vdr-1.3.29-orig/plugin.c vdr-1.3.29/plugin.c
--- vdr-1.3.29-orig/plugin.c	2005-01-30 15:05:20.000000000 +0100
+++ vdr-1.3.29/plugin.c	2005-08-20 19:37:41.000000000 +0200
@@ -99,6 +99,11 @@ 
   Setup.Store(Name, Value, this->Name());
 }
 
+bool cPlugin::Service(const char *Id, void *Data)
+{
+  return false;
+}
+
 void cPlugin::RegisterI18n(const tI18nPhrase * const Phrases)
 {
   I18nRegister(Phrases, Name());
@@ -372,6 +377,31 @@ 
   return NULL;
 }
 
+cPlugin *cPluginManager::CallFirstService(const char *Id, void *Data)
+{
+  if (pluginManager) {
+     for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) {
+         cPlugin *p = dll->Plugin();
+         if (p)
+            if (p->Service(Id, Data)) return p;
+         }
+     }
+  return NULL;
+}
+
+bool cPluginManager::CallAllServices(const char *Id, void *Data)
+{
+  bool found=false;
+  if (pluginManager) {
+     for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) {
+         cPlugin *p = dll->Plugin();
+         if (p)
+            if (p->Service(Id, Data)) found=true;
+         }
+     }
+  return found;
+}
+
 void cPluginManager::StopPlugins(void)
 {
   for (cDll *dll = dlls.Last(); dll; dll = dlls.Prev(dll)) {
diff -au vdr-1.3.29-orig/plugin.h vdr-1.3.29/plugin.h
--- vdr-1.3.29-orig/plugin.h	2005-01-30 15:03:48.000000000 +0100
+++ vdr-1.3.29/plugin.h	2005-08-21 03:00:29.000000000 +0200
@@ -50,6 +50,8 @@ 
 
   void RegisterI18n(const tI18nPhrase * const Phrases);
 
+  virtual bool Service(const char *Id, void *Data = NULL);
+
   static void SetConfigDirectory(const char *Dir);
   static const char *ConfigDirectory(const char *PluginName = NULL);
   };
@@ -88,6 +90,8 @@ 
   static bool HasPlugins(void);
   static cPlugin *GetPlugin(int Index);
   static cPlugin *GetPlugin(const char *Name);
+  static cPlugin *CallFirstService(const char *Id, void *Data = NULL);
+  static bool CallAllServices(const char *Id, void *Data = NULL);
   void StopPlugins(void);
   void Shutdown(void);
   };
diff -au vdr-1.3.29-orig/PLUGINS.html vdr-1.3.29/PLUGINS.html
--- vdr-1.3.29-orig/PLUGINS.html	2005-02-12 18:08:27.000000000 +0100
+++ vdr-1.3.29/PLUGINS.html	2005-08-20 20:34:40.000000000 +0200
@@ -26,6 +26,9 @@ 
 <!--X1.3.21--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
 Important modifications introduced in version 1.3.21 are marked like this.
 <!--X1.3.21--></td></tr></table>
+<!--X1.3.30--><table width=100%><tr><td bgcolor=#00AAAA>&nbsp;</td><td width=100%>
+Important modifications introduced in version 1.3.30 are marked like this.
+<!--X1.3.30--></td></tr></table>
 <p>
 VDR provides an easy to use plugin interface that allows additional functionality
 to be added to the program by implementing a dynamically loadable library file.
@@ -68,6 +71,9 @@ 
 <li><a href="#The Setup menu">The Setup menu</a>
 <li><a href="#Configuration files">Configuration files</a>
 <li><a href="#Internationalization">Internationalization</a>
+<!--X1.3.30--><table width=100%><tr><td bgcolor=#00AAAA>&nbsp;</td><td width=100%>
+<li><a href="#Custom services">Custom services</a>
+<!--X1.3.30--></td></tr></table>
 <li><a href="#Loading plugins into VDR">Loading plugins into VDR</a>
 <li><a href="#Building the distribution package">Building the distribution package</a>
 </ul>
@@ -866,6 +872,77 @@ 
 and then in the global VDR texts. So a plugin can make use of texts defined by the
 core VDR code.
 
+<!--X1.3.30--><table width=100%><tr><td bgcolor=#00AAAA>&nbsp;</td><td width=100%>
+<a name="Custom services"><hr><h2>Custom services</h2>
+
+<center><i><b>What can I do for you?</b></i></center><p>
+
+In some situations, two plugins may want to communicate directly, talking about things
+that VDR doesnt handle yet as mediator. For example, a plugin may want to use features 
+that a different plugin offers, or a plugin wants to inform other plugins about important
+things it does. To receive requests or messages, a plugin can implement the 
+following function:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre>
+virtual bool Service(const char *Id, void *Data = NULL);
+</pre></td></tr></table><p>
+
+<tt>Id</tt> is an unique identification string that identifies the service protocol.
+To avoid collisions, the string should contain a service name, the plugin name (unless
+the service is not related to a single plugin) and a protocol version number. 
+<tt>Data</tt> points to a custom data structure or is <tt>NULL</tt> to detect whether
+the plugin supports this service. For each id string there should be a specification
+that describes the format of the data structure, and any change to the format should 
+be reflected by a change of the id string.
+<p>
+The function shall return true for any service ID string it handles, and false 
+otherwise. The function shall not perform any actions as long as <tt>Data</tt> is 
+<tt>NULL</tt>. The plugins have to agreee in which situations the service
+may be called, for example whether the service may be called from every thread, or 
+just from the main thread. A possible implementation could look like this:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre>
+struct Hello_SetGreetingTime_v1_0 {
+  int NewGreetingTime;
+};
+
+bool cPluginHello::Service(const char *Id, void *Data)
+{
+  if (strcmp(Id, "Hello-SetGreetingTime-v1.0") == 0)
+  {
+    if (Data == NULL) return true;
+    GreetingTime = ((Hello_SetGreetingTime_v1_0*)Data)->NewGreetingTime;
+    return true;
+  }
+  return false;
+}
+</pre></td></tr></table><p>
+
+<p>
+To send messages to, or request services from a specific plugin, the plugin can directly call its
+service function:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre>
+Hello_SetGreetingTime_v1_0 hellodata;
+hellodata.NewGreetingTime = 3;
+cPlugin *Plugin = cPluginManager::GetPlugin("hello");
+if (Plugin)
+   Plugin->Service("Hello-SetGreetingTime-v1.0", &hellodata);
+</pre></td></tr></table><p>
+
+To send messages to, or request services from some plugin that offers the protocol, the 
+plugin can call the function <tt>cPluginManager::CallFirstService</tt>. This function
+will send the request to the first plugin that supports this service protocol. The 
+function returns a pointer to the plugin that handled the request, or <tt>NULL</tt>
+if no plugin handles the request.
+<p>
+To send a messages to all plugins, the plugin can call the function 
+<tt>cPluginManager::CallAllServices</tt>. This function will send the request to 
+all plugins that support this service protocol. The function returns <tt>true</tt> if 
+any plugin handled the request, or <tt>false</tt> if no plugin handled the request.
+
+<!--X1.3.30--></td></tr></table>
+
 <a name="Loading plugins into VDR"><hr><h2>Loading plugins into VDR</h2>
 
 <center><i><b>Saddling up!</b></i></center><p>