Пишемо skype бота на c # з модульною архітектурою

Давно вже засіла думка зробити таку собі ТУЛЗ-помічника, яка змогла б мені і курси валют вивести і погоду підказати і анекдот зацькувати, та все руки не доходили ... ну ви ж знаєте як це буває, вірно? Крім того, в моєму нескінченному списку із забавними ідеями, які непогано б коли-небудь реалізувати - був пункт «бот для скайпу 4fun».

Передмова

Потрібно лише все скомпіліть і в \ SkypeBotAdapterConsole \ bin \ Debug буде лежати готова Консолька, яку потрібно запустити для тестування (потрібна реєстрація бібліотеки skyp4com в системі + старий скайп). Далі в статті ці моменти розписані більш детально.

вступ


На чергових вихідних, трохи втомившись пиляти своє дітище - чергового вбивцю Фейсбук, я вирішив підібрати що-небудь для душі та реалізувати. Вибір припав на бота для скайпу. Вирішив писати відразу з доробком на розширюваність, щоб колеги могли дописати ті модулі бота, які потрібні безпосередньо їм.
До слова, перебуваю я в одному Skype чаті, який в свою чергу складається з друзів, знайомих, та колег і іменумий Men's club. Був створений за часів спільної роботи на одному з проектів, та так якось і прижився в наших контакт-листах, приймаючи на себе роль чоловічої болталки. Саме для цього чату я і написав бота, щоб трохи повеселити народ, та внести невелику родзинку.

ставимо завдання


І так. визначимося з тим, що хотілося б мати в кінцевому підсумку:

Дослідження предметної області

Зробивши задумане обличчя, я протягом півгодини накидав код, який кожні пару секунд кликав на чат, копіював в буфер повідомлення і таким чином взаємодіяв з ui оболонкою. Подивившись на цього Франкенштейна, моє серце стислося і я затиснув backspace на добрих 10 секунд. «Та не може бути, щоб не знайшлося рішення краще» - промайнуло в голові, а руки самі потягнулися до клавіатури.

Виникла ідея прикрутити стару api бібліотечку до старого skype, але, як ви знаєте - Microsoft і тут підклав нам рожеве тварина, заборонивши використовувати старі версії скайпу. Вивчивши кілька статей я прийшов до висновку, що існують окремі старі portable версії, перероблені умільцями до працездатного стану зі збереженням старого функціоналу. І таки да, запустивши скайп на виртуалке, я переконався, що стара api бібліотека таки працює з трохи більш старим скайп.

Реалізація


І так, для реалізації задуманого нам буде потрібно:

- Skype4COM.dll - це компонент ActiveX, який надає API для спілкування зі Skype'ом
- Interop.SKYPE4COMLib.dll - проксі Ліба для взаємодії з Skype4COM.DLL з .net коду
- Запущений Skype (підійде наприклад версія 6.18, пробував і на 4.2, але там ще не було підтримки чатів)
- Кефір і вівсяне печиво

Реєструємо Skype4COM.DLL в системі. Найпростіший спосіб - створити .bat файл і вписати туди


Кладемо його поруч з dll і запускаємо батник. Надкушує печеньку, запиваємо кефіром і потираємо руки, тому що десята частина справи зроблена.

Далі нам потрібно якимось чином перевірити чи працює воно взагалі.

Взаємодія зі скайп


Створюємо консольний додаток, підключаємо Interop.SKYPE4COMLib.dll і пишемо наступний нехитрий код:


Запускаємо, просимо кого-небудь нам написати в скайпі - в консольку виводиться текст співрозмовника. Win. Тягнемося до ще однієї печеньки і доливаємо в кружку кефіру.

пишемо модулі


І так, залишилося зовсім небагато. Нам потрібно реалізувати бота таким чином, щоб підключати додаткові модулі з командами для бота було простіше ніж змастити кулер в блоці живлення.

Створюємо library проект і назвемо його, припустимо HelloBotCommunication. Він буде служити мостом між модулями і ботом. Розміщуємо туди три інтерфейсу:

Він буде відповідати за класи-обробники повідомлень.

де CallCommandList це список команд за якими буде викликаний HandleMessage, CommandDescription потрібен для виведення опису в команді! modules (про це нижче) і HandleMessage - де модуль повинен обробити входять параметри (args), передавши відповідь в коллбек sendMessageFunc

Він буде відповідати за реєстрацію наших оброблювачів.

Він буде відповідати за додаткову інформацію про клієнта, в даному випадку - про скайпі, якщо така необхідна оброблювачу.


Сенс цього всього ось в чому: розробник створює свою .dll, підключає нашу бібліотеку для комунікації, успадковується від IActionHandler і IActionHandlerRegister і реалізує потрібний йому функціонал не думаючи про все те, що лежить вище.

Приклад у вигляді модуля команди «скажи», який змусить бота сказати все що буде після самої команди.

Пишемо тіло бота


Модуль є, бібліотека для зв'язку є, залишилося написати головного винуватця торжества - мсьє бота і все це якось пов'язати. Так легко - скажете ви і збігає на кухню за другим пакетом кефіру. І матимете рацію.

Назвав я його HelloBot і створив окремий library проект. Суть класу полягає в пошуку потрібних .dll з модулями і роботі з ними. Робиться це через

Тут хочу трохи застерегти вас. Це за великим рахунком рішення в лоб і потенційно є дірою в безпеці. По-хорошому потрібно створювати окремий домен і давати тільки потрібні права при виконанні чужих модулів, але ми люди наївні і припускаємо, що весь код перевірений, а модулі написані з кращих спонукань. (Правильне рішення не писати велосипед, а заюзать наприклад, MEF)

Після реєстрації створення об'єкта у нас будуть в розпорядженні префікс команди (за замовчуванням "!") І маска для пошуку .dll модулів. А так же метод HandleMessage в якому і твориться вся магія.
Магія полягає в отриманні вхідного повідомлення, якихось специфічних даних від клієнта (якщо такі є) і коллбека на відповідь. Так само введений список системних команд ( «help» і «modules»), які дозволяють побачити ці самі команди в першому випадку і список всіх підключених модулів у другому.
Виконання модуля виділено в окремий тред і обмежена за часом виконання (за замовчуванням в 60 секунд), після чого тред просто припиняє своє існування.

Бот готовий, залишився останній штрих - зв'язати його з консолним додатком, яке обробляє повідомлення від скайпу.

Кінцевий варіант Program.cs для консольного застосування

Ось власне і все. За пару днів колегами і мною були написані пару модулів. Приклади під катом.

bash виводить випадкову цитату з баша
!ithap виводить випадкову IT історію
. погода показує поточну погоду в Мінську
!say говорить те, що накажете
!calc виконує арифметичні операції (через NCalc бібліотеку)

сиськи забирає рандомних фотку з тумблера. Ну а як же без них. До слова, одна з найпопулярніших команд в чаті))


. курс виводить поточні курси та через параметри може деталізувати висновок. Обмін євро на usd і тд.
та інші.

відомі проблеми
На жаль, щось у протоколі судячи з усього змінилося і бот не бачить нові групові чати. Старі чомусь підхоплює на ура, а от з новими проблема. Я намагався копатися, але рішення не знайшов. Якщо хто підкаже як побороти цю болячку, буду вдячний.
Так само іноді буває, що повідомлення губляться і скайпу потрібен «прогрів», після чого він заводиться і адекватно реагує на всі наступні повідомлення.

Дякую за увагу, сподіваюся перший млинець не пішов грудкою і матеріал виявився корисним.