Hotplug manager : gestionnaire de plugins interchangeables en live (ou "à chaud")

Description

Gérer simplement des plugins sans redémarrer l'application. Galère !
Et ben plus maintenant !

Je souhaitais une application qui puisse recharger en live un plugin lorsqu'il est mis à jour.
Autrement dit :

-- Dans un dossier, disons ... "plugins", je met les plugins que je veux charger au démarrage.
-- Quand je décide d'updater un plugin, je met simplement la nouvelle dll dans un autre dossier, disons "updates". Et là c'est magique, le gestionnaire reconnait le plugin, vérifie que c'est une version plus récente que celle qui tourne, et change le plugin en live.
Le changement s'effectue en demandant au plugin de se mettre en pause puis de sauvegarder ses donnés.
La sauvegarde sera fournit à la nouvelle version au moment de son démarrage.

La petite histoire (ou "ma life" ... mais non partez pas !)

A l'origine je souhaitais faire un client irc en C#... avec un bot :-D
Pourquoi ? Simplement parce que :
--> j'en ai soupé de l'irc scripting...
--> J'avais envie de m'amuser à developper un bot "intelligent"
(les sources ça sera pour beaucoup plus tard :)
--> Et puis comme on peut compiler le C# en live on peut creer une dll en live ...
Donc on peut remplacer l'irc scripting (ta tatataaaaaaaa ! \o/)
(quoi ? déja dit... mais nan j'avais pas assez insisté c'est tout !)

Au début je m'étais jeté dans le code ... et j'étais obligé de redémarrer mon client pour que la nouvelle version de mon bot soit executée. Les déco et reco incessantes commençaient doucement à énerver les irciens sur les channels.
Donc je me suis dit et pourquoi pas faire un "truc" qui marche en live (non "truc" c'est pas ringard ... >:p)
En dehors de mes hobbies qui consiste à réinventer la roue, je me suis dit aussi que ça pourrait avoir des applications fort sympathiques (genre patchage de code à distance sur un serveur web ... sécurisé bien sûr :D )

Le bémol :

Le manager ne gère pas les droits d'écriture, éxécution, etc ...
Tout simplement parce que cette lib est destiné à un usage personnel.
Autrement dit y'aura pas de Kevin pour faire un plugin-virus :) ...

Passons au zip :

3 dossiers pour 3 modules :

PluginManagerTest :
Application de base gérant les plugins
Une simple form est lancé ..
L'application nécessite une référence au module PluginManagement

PluginManagement :
Contient tout ce qui est nécessaire à la réalisation d'un plugin manager
Interfaces.cs : Les interfaces nécessaires à la communication entre le plugin manager et les plugins (à rédéfinir par vous).
Loader.cs : Le loader qui s'occupe de charger les assemblies dans un domaine d'application différent.
Manager.cs : Le plugin manager, enfin ! C'est la classe qui gere les plugins et utilise Loader.cs
Cette classe est celle qui est utilisé par l'application.

MyPlugin:
Définit un plugin de base.
Ce module nécessite une référence au module PluginManagement
(en réalité il à seulement besoin d'Interfaces.cs mais j'avais pas envie de faire un quatrième module)

Principe: Dans le dossier plugins sont stockés les plugins chargés par l'application
Quand on met une dll du même nom dans le dossier update,
l'application le détecte et remplace le plugin en live.

Cas de cette application :
L'application charge "MyPlugin.dll" dans "plugins" quand on clic sur "Charger le plugin"
A chaque fois que l'on clique sur "Recharger le plugin" l'application regarde si
le fichier "MyPlugin.dll" existe dans le dossier "update".
Si il existe alors il est déplacé dans "plugins" et remplace l'ancienne version.
Les anciennes versions du plugin sont sauvés sous la forme MyPlugin.dll.backup<i>,
ou "i" correspond à la vieillesse du plugin (1, 2, 3 ...)

Source / Exemple :


// Comme ça me gonfle de toujours voir écrit "dans le zip"
// Je vous montre un peu à quoi ça ressemble au final :
// (A savoir que c'est du copié/collé d'une partie de ce qu'il y a le zip !)

// Dans la classe  de la form :
// Définit les dossiers dont j'ai parlé dans la description
Manager plugin_manager = new Manager("plugins", "update");

// Chargement d'un plugin au demarrage : 
int my_plugin_id = plugin_manager.ImportPlugin(@"plugins\MyPlugin.dll");
if (-1 == my_plugin_id)
   MessageBox.Show("Erreur : Plugin non valide ! (ne respecte pas l'interface en general)");

/ Toute les 3 secondes le gestionnaire check les updates de tous les plugins
// Une valeur de 0 arrête la vérification.
plugin_manager.IntervalUpdate = 3000; 

// Tester soit même l'update du plugin :
if (plugin_manager[my_plugin_id].CheckUpdate())
   MessageBox.Show("patché !);

// "Mais t'es un ouf !"
// "Moi je suis flemmard mais j'ai quand meme des patchs ultra sensible."
// "Je veux que tous les plugins soit updaté automatiquement ...
//  sauf un plugin en particulier que je veux uploader manuellement !"
// "Du calme petit scarabé !"
plugin_manager[my_precious_plugin_id].AutoUpdatable = false;
// Ce qui n'empêche pas de faire l'appel à CheckUpdate !

Conclusion :


Bon ben voila :)
Y'a pas mal de commentaires dans les sources (en anglais souvent).
Je suis ouvert à toutes critiques (constructives) !

Pour tester il existe trois versions de myplugin.dll (dans le dossier "bin/Debug/update").
Renommer les versions 2 et 3 (la 1 étant celle chargée au démarrage) en "MyPlugin.dll".
Les fichiers disparaissent à chaque fois (normal ! C'est le gestionnaire qui les déplacent).
Bonne chance !

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.