Мастер-класс: Создание Telegram-бота для декомпиляции файлов 1С на OneScript и Осени
Содержание
- Введение
- Почему Осень?
- Техническое задание
- Архитектура
- Создание структуры проекта
- Добавляем бота
- Предварительные итоги
- Работаем с секретами
- Добавляем логирование
- Работа с интерфейсом
- Разбор бинарников
- Публикация файлов
- Подключаем базу данных
- Асинхронное выполнение
- Итоги и домашнее задание
Введение
Приветствую всех! Меня зовут Чегодаев Павел, и я хочу вместе с вами пройти мастер-класс по разработке бота на OneScript и фреймворке Осень.
На написание этой статьи меня вдохновила публикация От базовой библиотеки до полного расцвета с ОСенью. Разработка базовой версии. Поскольку вторая часть пока не вышла, я возьму на себя смелость продолжить начинания Владимира, но давайте выберем новую тему.
Важно! Без понимания первой части вам будет сложно понять, о чем тут речь.
Почему Осень?
Есть желание расширять кругозор после 15 лет работы с 1С. В Осени многие концепции заимствованы из Java — это стало отличным поводом изучить новые подходы, оставаясь в знакомой среде языка 1С.
Техническое задание
Цель:
Мобильно получать код из файлов формата 1c(.cf .cfe .epf .erf) на телефон.
Описание:
Создать Telegram-бота, который на вход принимает бинарные файлы, а на выходе возвращает исходный код.
Приложение должно разворачиваться в контейнере Docker.
Чтение кода должно быть реализовано удобно.
Архитектура
Любая разработка начинается с архитектуры решения. Давайте определим основную функциональность, которая должна быть реализована:
- Обработка сообщений в боте
- Разбор файлов на исходники
- Публикация исходников
Попробуйте самостоятельно нарисовать диаграмму классов, а затем мы сравним результаты.
Как мы все знаем, в прошлом писался код с «километровыми» методами, которые выполняли множество задач одновременно. Мы не будем следовать такому подходу. Паттернов и подходов к разработке приложений много, но давайте возьмем за основу MVC.
Попробуем разделить наше приложение на слои, чтобы они были независимы.
Что такое MVC:
M (Model) — здесь работа с БД и бизнес-логика.
V (View) — так как у нас Telegram-бот, то за представление пусть он и отвечает.
C (Controller) — это наш мостик между представлением и бизнес-логикой.
У меня получилось так:
Для удобства я буду диаграммы также оставлять в исходном виде
@startuml
class Controller
class Model
package Controller {
class БотТелеграмм
БотТелеграмм : ПроверитьСообщения()
}
package Model {
class МенеджерПубликаций
class Декомпилятор
class Публикатор
}
БотТелеграмм --|> МенеджерПубликаций
МенеджерПубликаций --|> Декомпилятор
МенеджерПубликаций --|> Публикатор
Декомпилятор : РазобратьФайл()
Публикатор : Опубликовать()
МенеджерПубликаций : ОбработатьФайл()
@enduml
Давайте создадим структуру проекта.
Что бы я ни делал, я всегда начинаю с команды git init — это позволит впоследствии версионировать код и, возможно, поделиться им с вами. :)
Осенний Hello world
Перед тем как погрузиться с головой в наше приложение, давайте напишем что-то простое. Любое приложение на Осени начинается с точки входа. Создадим три файла:
//Файл main.os
#Использовать "."
#Использовать autumn
Поделка = Новый Поделка();
Поделка.ЗапуститьПриложение();
ПриветМир = Поделка.НайтиЖелудь("ПриветМир");
ПриветМир.Поздороваться();
//Файл Классы\ПервыйЗапущенныйКласс.os
&Пластилин
Перем ПриветМир;
&Рогатка
Процедура ПриСозданииОбъекта()
КонецПроцедуры
Процедура ПриЗапускеПриложения() Экспорт
ПриветМир.Поздароваться();
Сообщить("При запуске приложения");
ПриветМир.ФразаПриветствия = "Hello, world!";
КонецПроцедуры
//Файл Классы\ПриветМир.os
Перем ФразаПриветствия Экспорт;
&Желудь
Процедура ПриСозданииОбъекта()
ФразаПриветствия = "Привет, мир!";
КонецПроцедуры
Процедура Поздороваться() Экспорт
Сообщить(ФразаПриветствия);
КонецПроцедуры
Запустим oscript main.os
И увидим вывод:
Что тут происходит? В момент ЗапускПриложения() у нас происходит регистрация наших компонентов.
Компоненты у нас называются желуди, но пусть тебя не отвлекает нейминг от сути. В примере выше компонент - Класс ПриветМир! Что бы его объявить - у метода ПриСозданииОбъекта() мы установили аннотацию &Желудь — так мы указали, что этот класс мы можем получить в любой момент из Контейнера, создаваемого Осенью.
Когда мы пишем &Пластилин, мы получаем экземпляр нашего объекта.
Если говорить простыми словами, грубо и с оглядкой на 1С, то компоненты могут быть обработками, они создаются и хранятся в памяти, мы в любой момент можем к ним обратиться. Давайте представим, что у нас есть глобальный контекст и есть глобальная переменная с типом Соответствие. Ключ — имя обработки, значение — сам объект. В любом месте мы можем получить его и использовать.
Вернемся к Осени! Когда мы на какой-то класс вешаем аннотацию &Рогатка - этот класс создается в момент запуска. Если разобрать по шагам, у нас получается:
- Поделка.ЗапуститьПриложение();
- Так как у ПервыйЗапущенныйКласс аннотация &Рогатка Он создается следующим.
- У класса есть &Пластилин - ПриветМир , мы создаем его и помещаем в контекст приложения.
- При создании ПриветМир у свойства ФразаПриветствия устанавливается значение "Привет, мир!" по этому когда
Процедура ПриЗапускеПриложения() Экспорт
ПриветМир.Поздароваться();
...
В консоль выводится "Привет, мир!"
- Мы устанавливаем новое значение свойству "ПриветМир.ФразаПриветствия = "Hello, world!";
- В строке ПриветМир = Поделк а.НайтиЖелудь("ПриветМир"); Мы достаем уже существующий компонент.
- ПриветМир.Поздароваться(); у нас уже вывод "Hello, world!"
Если бы не Осень, нам бы пришлось продумывать, как передавать объекты свойства классов.
....Но вернемся к нашей задаче!
Создание структуры проекта
Ожидаемая структура:
Здесь мы сразу подключаем папки "/src/controller" и "/src/core" к нашему приложению, а также фреймворк Осень, который впоследствии значительно упростит разработку.
Но что произойдет в момент вызова ЗапуститьПриложение()? Как сделать, чтобы наш бот заработал?
Мы должны создать класс, у которого будет аннотация &Рогатка, это мы обсуждали уже выше. Давайте добавим такой класс к нашему проекту.
Теперь разберем код. У нас есть класс, который реализует логику общения с Telegram, мы его назвали ТелеграммБот. Чтобы начать работать с этим классом, у нас есть два варианта:
- Создать экземпляр в коде:
ТелеграммБот = Новый ТелеграммБот;
ТелеграммБот.Запустить()
- Внедрить через механизм внедрения зависимостей Осени.
Внедрять можно тремя способами:
Через свойства, как в варианте выше:
&Пластилин
Перем ТелеграммБот; // Класс для запуска Telegram-бота
Через специальный метод-сеттер:
Перем ТелеграммБот;
&Пластилин
Процедура УстановитьТелеграммБот(Значение) Экспорт
ТелеграммБот = Значение;
КонецПроцедуры
или через конструктор
В каких случаях это может быть полезно? Например, у нашего класса ТелеграммБот есть поле Токен и разные методы ОтправитьСообщение(), ОтправитьКартинку() и т. д.
В одном месте мы заполняем токен, потом в любых других местах через аннотацию &Пластилин мы получаем экземпляр этого класса, а он уже настроен так, как нам нужно. Нам не надо думать о том, как этот экземпляр передать в нужные нам классы.
Добавляем бота
Нам нужно как-то взаимодействовать с ботом. Варианта два: либо писать самому, либо использовать существующие библиотеки.
Хороший программист стремится использовать готовые решения — давайте использовать готовую библиотеку. Мне нравится библиотека Антона - ОПИ, поражает его подход к написанию и развитию этой библиотеки. Внимание ко всем мелочам.
Теперь разберем, что тут написано.
Мы подключили oint (ОПИ), чтобы использовать уже готовые интеграции с Telegram. У метода ПриСозданииОбъекта() установили аннотацию &Желудь — напомню, так мы указали, что этот класс мы можем получить в любой момент из Контейнера, создаваемого Осенью. Именно так мы и сделали в классе Запускатор.
Предварительные итоги
На этом этапе у нас с вами готова основа, наш бот даже сейчас будет отвечать эхом. Можно запустить отладку. Для удобства пропишем в отладку запускаемый файл — тогда, независимо от позиционированного в проекте файла, все равно запустится нужный.
Проверяем наш бот — работает! УРА!
Работаем с секретами
Внимательный читатель наверняка заметил, что очень нехорошо писать токен в коде, особенно когда потом проект идет в публичный репозиторий GitHub. Существуют даже роботы, которые сканируют GitHub на предмет различных секретов. Мы могли бы создать конфигурационный файл с настройками, запрограммировать его чтение, но Осень все сделала за нас.
Нам всего-то нужно создать файл autumn-properties.json и указать все секреты там. Не забывайте указывать его в .gitignore, иначе секреты в итоге все равно попадут в публичный доступ.
Попробуем создать конфигурационный файл:
Добавили autumn-properties.json.
{
"TELEGRAMM": {
"TOKEN": "7967956539:"
}
}
Теперь, чтобы получить доступ к нашей «Настройке», нам нужно воспользоваться аннотацией &Деталька.
Добавляем логирование
Как и в первой части, нам пора позаботиться о логировании нашего приложения. Вместо того чтобы везде писать Сообщить(), давайте используем более продвинутую систему логирования.
Создание класса ЛогАннотация
Добавим библиотеку работы с логами #Использовать autumn-logos, прочитать про нее подробнее можно тут.
Для удобства работы с логами создадим специальный класс ЛогАннотация.os в папке src/core/Классы/. Благодаря функциональности Собственные аннотации это возможно.
Теперь для подключения лога достаточно в классе добавить &ЛогПубликация Перем Лог;. Попробуем переписать класс Запускатор с учетом логов.
Визуально разницу можно увидеть по коммитам.
Работа с интерфейсом
Пора начинать делать то, ради чего все и затевалось, — разбор исходников. Мы предполагаем, что пользователь может прислать в бот или сообщение, или файл. Думаю, стоит начать с обработки того, что он пришлет. Если пришлет сообщение — скажем, что работаем только с файлами. Если файл — то пойдем и разберем его.
Но как это написать? На ум первое, что приходит, — что надо доработать класс ТелеграммБот. Примерно так:
Если ЭтоСообщение(Сообщение) Тогда
// Сообщить, что мы работаем только с файлами
ИначеЕсли ЭтоФайл(Сообщение)
// Разобрать и вернуть исходники
КонецЕсли;
Но я предлагаю пойти по другому пути: вдруг мы будем развивать наше решение, и у нас будет больше вариантов работы с сообщениями — писать все в одном классе неудобно. Возьмем паттерн «Команда» и попробуем его применить.
Идея следующая: мы получаем от бота «сообщение», проверяем по условиям, какая команда нам подходит. Та команда, которая подошла, занимается обработкой сообщения и либо отправляет в Менеджер публикаций, либо, например, сообщает: «В данный момент обработка текстовых сообщений не поддерживается».
Попробуйте перерисовать диаграмму классов, а потом сравним :)
Теперь поменяем наш `ТелеграммБот` с учетом команд:
Тут есть что обсудить.
Во-первых, так как я планирую в будущем использовать больше команд, я заложил под это основу.
Командам я дал прозвище — алиасы. Теперь я могу обращаться сразу ко всем желудям с одинаковым прозвищем, например обходить их в цикле. Если бы не эта возможность, мне пришлось бы реализовывать паттерны фабрики и стратегии, например. Тут же Осень все взяла на себя!
&Пластилин(“Команда”, Тип = “Массив”)
Перем Команды;
Для работы с командами я определил единый интерфейс, теперь я хочу, чтобы он проверялся, ну как во «взрослых» языках. ))
Для этого есть библиотека extends, я создал класс ВалидаторИнтерфейсов.os.
Кстати в Осени обещают реализовать проверку интерфейсов на уровне самого фреймворка.
В классе выше я проверяю интерфейс всех команд, которые были добавлены с одинаковым прозвищем.
Также я заложил возможность расширять валидируемые интерфейсы (ВалидируемыеИнтерфейсы()), но теперь надо понять момент, когда нужно выполнять эту проверку. На помощь приходит аннотация &Приемка.
Специальный тип желудя для обработки определений желудей.
Аналог &Напильника для ОпределениеЖелудя. Срабатывает каждый раз, когда в контекст добавляется новое определение желудя. При добавлении самой Приемки в контекст, все ранее добавленные определения желудей передаются в Приемку для проверки.
Когда в ПриДобавленииОпределенияЖелудя попадает желудь, мы проверяем его прозвище, и если прозвище «Команда», мы проверяем его интерфейс на соответствие специальному классу ИнтерфейсКоманда.os, у которого должна быть аннотация &Интерфейс и требуемые методы. Важно: тут также учитывается количество параметров.
Если обратили внимание, то, наверное, заметили, как передаются параметры с команды до менеджера публикаций. В менеджере публикаций я определяю ДТО для обмена данными между нашими слоями (грубо говоря, структуру) — МенеджерПубликаций.НовыйДанныеДляРазбораФайла();. Я решил передавать на слой логики побольше информации, а не только двоичные данные. Позже, думаю, мне это понадобится.
Также внимательный читатель увидел аннотацию &Число — это тоже одна из «фишек» фреймворка Осени — типизировать переменные. Для того чтобы это использовать, нам нужно подключить autumn-annotation-types.
Текущий вид проекта
Также изменения можно легко отследить по коммитам репозитория — я постарался фиксировать доработки шагами. Коммиты
Разбор бинарников
Мы подошли к теме разбора бинарников. На текущий момент я знаю следующие методы:
- С помощью платформы 1С в пакетном режиме
- С помощью утилиты ibcmd
- С помощью библиотеки v8unpack
- С помощью saby v8unpack — консольная утилита для сборки и распаковки.
Мой выбор пал на последний вариант: «пакетник» работает долго, с ibcmd у меня свои счеты, а библиотека v8unpack раскрывает исходники до уровня, когда все файлы представлены в виде идентификаторов.
Для того чтобы разбирать файлы, я создал две папки — куда буду класть исходники и куда все буду распаковывать. Чтобы папки были в репозитории даже когда они пустые, я поместил в них пустой файл .gitkeep.
Давайте подумаем, с какими сложностями мы можем столкнуться?
Верно. Что будет, если с ботом будут общаться параллельно, а файлы будут одинаково называться? Чтобы их разделить, я решил использовать номер сообщения как «идентификатор» сеанса.
Изначально я взял декомпилятор из релизов в виде exe-исполняемого файла. Какие это наложит ограничения? Верно! Я не смогу использовать этот функционал в Docker, поэтому я реализовал два варианта: один — с помощью exe (нативно может запуститься на Windows), и py-скрипт, требующий установки Python.
Добавил настройку в autumn-properties.json. На уровне соглашения нужно договориться, что настройка "UNPACK" будет иметь два значения: "py" и "exe"
Я решил сделать компанейский желудь. Что это значит? При получении его я буду получать новый экземпляр класса, мне это нужно так как у него по-разному должны будут заполнены свойства пути к файлу.
Поля, которые будут заполняться по-разному в конструкторе, я отметил с помощью аннотации &Блестяшка. Теперь, когда я буду «доставать» свой желудь, я буду дозаполнять его поля:
Обратим внимание, что такой желудь надо пометить аннотацией &Табакерка. А в момент использования мы вызываем код: КомандаЗапускаДекомпилятора.Достать(Параметры);.
Публикация файлов
Как удобно просматривать код на телефоне?
Вариант 1: Отправлять сырой текст в Telegram.
Минусы: Нечитаемо, ограничение на 3000 символов.
Вариант 2: Использовать Paste1C. Замечательный сервис Paste 1C, где изначально я все и реализовал.
Минусы: Что делать, когда у обработки несколько форм и модуль объекта — кидать много ссылок? Это не всегда удобно, особенно когда файлов много.
Вариант 3: Файлообменники.
Минусы: Неудобно для быстрого просмотра.
Вариант 4: Gist GitHub. + Позволяет сравнивать правки между версиями. + Есть доступ по ссылке (аналог Google Docs). Код виден только тем, кому вы дали ссылку.
Минусы: Тоже есть ограничения, вроде 100 файлов.
Вариант 5: Репозиторий.
Минусы: Нет возможности создавать доступ по ссылке: или всем видно, или приватно с добавлением доступов.
Итог: Я выбрал вариант 4, но надо сделать так, чтобы легко можно было расширить возможности и публиковать еще куда-то.
Мы уже знаем, как нам работать с разными классами, которые объединены одним алиасом, добавляем нужный интерфейс в валидатор, описание интерфейса и классы для публикации.
Не буду подробно останавливаться на коде, только скажу, что я тут использую библиотеку 1connector, чтобы упростить написание запросов.
Также в настройки я добавил свойство "SHARESERVICE": ["ПубликаторGist", "ПубликаторЕщеКакойНибудь"], чтобы на их уровне мы могли определять, где будет публиковаться код. Если что-то из листинга непонятно — пишите в комментарии, и я расширю статью пояснениями.
Также для Gist я реализовал разбор списка файлов и формирование оглавления, чтобы проще было в них орентироваться, пишу в отдельный gist.
Подключаем базу данных
У нас с вами почти все готово: файлы отправляются, код присылается — чего еще желать?
Давайте смоделируем такую ситуацию: мне отправляют обработку, я ее смотрю и оставляю свои комментарии. Программист правит код и отправляет обратно — было бы удобно заменять публикацию новой. Мало того, возможности Gist нам покажут, какой код был изменен. Но как это сделать? Нам же надо хранить где-то информацию о том, какие публикации были уже отправлены. Предлагаю подключить к нашему боту базу данных. И тут тоже Осень готова нам помочь.
Нарисуем взаимодействие пользователя с Telegram.
- Будем сохранять публикации — тогда, когда в следующий раз нам нужно будет ее обновить, мы будем знать какую.
- Будем сохранять информацию о входящем файле, так как с ним мы будем взаимодействовать уже после того, как показали клавиатуру.
Итого, нам нужно две таблицы: ИсторияПубликаций и ИсторияФайлов.
Подключаем библиотеку autumn-data. Для этого нам нужно создать описание таблиц — сделаем это в новой папке data.
Внесем настройки для работы с библиотекой в autumn-properties.json:
"data": {
"ИсточникиДанных": {
"ТипКоннектора": "КоннекторJSON",
"СтрокаСоединения": "./DataBase"
}
},
// src\data\Классы\ИсторияПубликаций.os
// BSLLS:ExportVariables-off
&Идентификатор
&ГенерируемоеЗначение // Заполняется автоматически при сохранении сущности
&Колонка(Тип = "Целое") // Хранит целочисленные значения
Перем Идентификатор Экспорт; // Имя колонки в базе - `Идентификатор`
&Колонка(Тип = "Целое")
Перем ИДПользователя Экспорт; // Колонка `ИДПользователя`
&Колонка(Тип = "Строка")
Перем ИмяФайла Экспорт; // Колонка `ИмяФайла`
&Колонка(Тип = "ДатаВремя")
Перем ДатаОтправки Экспорт; // Колонка `ДатаОтправки`
&Колонка(Тип = "Строка")
Перем ИДПубликации Экспорт; // Колонка `ИДПубликации`
&Колонка(Тип = "Строка")
Перем ИДФайла Экспорт; // Колонка `ИДФайла`
&Сущность(ИмяТаблицы = "ИсторияПубликаций")
Процедура ПриСозданииОбъекта()
КонецПроцедуры
// src\data\Классы\ИсторияФайлов.os
// BSLLS:ExportVariables-off
&Идентификатор
&ГенерируемоеЗначение
&Колонка(Тип = "Целое")
Перем Идентификатор Экспорт;
&Колонка(Тип = "Строка")
Перем ИДФайла Экспорт;
&Колонка(Тип = "Строка")
Перем ИмяФайла Экспорт;
&Сущность(ИмяТаблицы = "ИсторияФайлов")
Процедура ПриСозданииОбъекта()
КонецПроцедуры
У меня в VS Code подключен BSLLS, и он ругается, что нужно описать значение переменных. Мне кажется, тут это делать излишним. Чтобы он не ругался, предлагаю отключить в этом файле эту проверку — // BSLLS:ExportVariables-off.
Обратите внимание на аннотации &Идентификатор и &ГенерируемоеЗначение: при записи в таблицу мы автоматически будем генерировать идентификатор.
Теперь мы должны описать логику записи и получения данных из таблиц. Покажу на примере таблицы ИсторияПубликаций.
// src\data\Классы\ХранилищеИсторияПубликаций.os
// BSLLS:UnusedParameters-off
#Область ОбъявлениеПеременных
&Родитель
Перем ХранилищеСущностей;
#КонецОбласти
#Область ПрограмныйИнтерфейс
&ХранилищеСущностей("ИсторияПубликаций")
Процедура ПриСозданииОбъекта()
КонецПроцедуры
&МетодЗапроса
Функция ПолучитьОдноПоИдентификаторРавно(Идентификатор) Экспорт
Возврат Неопределено;
КонецФункции
&МетодЗапроса
Функция ПолучитьПоИДПользователяРавноИИмяФайлаРавно(ИДПользователя, ИмяФайла) Экспорт
Возврат Неопределено;
КонецФункции
Функция СохранитьЗаписьОФайле(ДанныеФайла) Экспорт
ИсторияПубликаций = ХранилищеСущностей.СоздатьЭлемент();
ИсторияПубликаций.ИДПользователя = ДанныеФайла.ИДПользователя;
ИсторияПубликаций.ИмяФайла = ДанныеФайла.ИмяФайла;
ИсторияПубликаций.ДатаОтправки = ТекущаяДата();
ИсторияПубликаций.ИДПубликации = ДанныеФайла.ИДПубликации;
ИсторияПубликаций.ИДФайла = ДанныеФайла.ИДФайла;
ИсторияПубликаций.Сохранить();
Возврат ИсторияПубликаций;
КонецФункции
#КонецОбласти
К этому классу можно относиться, как, например, мы относимся в 1С к модулю менеджера. &МетодЗапроса — это аннотация, которая позволяет генерировать необходимый нам запрос «под капотом». Например, ПолучитьПоИДПользователяРавноИИмяФайлаРавно() позволяет найти запись по двум полям, и нет необходимости описывать отборы.
ПолучитьОдноПоИдентификаторРавно можно не объявлять, он есть нативный, предоставляемый классом-родителем ХранилищеСущностей, через ПолучитьОдно(Идентификатор)
Асинхронное выполнение
До сих пор у нас была обработка в один поток, то есть если кто-то кидает большой файл, другие должны его подождать. Я думаю, что это не дело, давай исправлять! И опять к нам на помощь приходит Осень и ее библиотека autumn-async
Надо всего лишь добавить в main.os #Использовать autumn-async, а метод, который мы хотим запускать асинхронно - пометить аннотацией &Асинх, что может быть проще?
ВАЖНО, из-за существующий ограничений, асинхронный метод должен находиться в другом классе, иначе чуда не произойдет)
Итоги и домашнее задание
Небольшая демонстрация готового функционала
У нас осталось всего несколько шагов до запуска своего бота. Надо подготовить packagedef — он поможет собрать пакет в Docker-контейнере.
Создаем Dockerfile, который на основании образа onescript:dev развернется, установим Python, скопируем файлы, относящиеся к проекту, и запустим наш бот.
Проверяем работоспособность.
docker build -t sharebot -f docker/Dockerfile . docker run sharebot
Кидаем расширение, публикуем, вносим исправления, например в коде вместо привет - пишем пока, отправляем еще раз и видим все изменения.
Я обещал домашнее задание? Да!
- Хороший тон для любого опенсорс-проекта — это наличие тестов. Давайте придумаем тесты для нашего бота и обсудим их в комментариях к статье.
- У нас не все хорошо с ответственностью она растеклась по командам, подумай можем ли мы сделать отдельный желудь ОтправляторCообщений который будет знать токен и отправлять сообщения пользователь
- Задача со звездочкой, сделать ОтправляторCообщений с прозвещем Уведомдения тогда например мы можем отвечать не только в Telegram но и в почту
Упоминание функционала Осени
Желудь
Аннотация &Желудь используется для регистрации классов в контейнере зависимостей Осени. Примеры использования: + Класс ТелеграммБот — регистрация бота в контейнере + Класс Запускатор — регистрация основного запускающего класса + Класс Декомпилятор — регистрация класса для разбора файлов + Классы публикаторов — регистрация различных способов публикации
Приемка
Аннотация &Приемка используется в классе ВалидаторИнтерфейсов для обработки определений желудей при их добавлении в контекст. Позволяет валидировать интерфейсы команд и публикаторов.
Пластилин
Аннотация &Пластилин используется для внедрения зависимостей. Примеры: + В классе Запускатор — получение экземпляра ТелеграммБот + В классе КомандаФайл — получение МенеджерПубликаций + В классе ТелеграммБот — получение массива команд
Свои аннотации
Создание собственных аннотаций показано в разделе Добавляем логирование на примере аннотации &ЛогПубликация для работы с логами.
Типизация переменных
Аннотация &Число и другие типы используются для типизации переменных. Подключение библиотеки autumn-annotation-types описано в разделе Работа с интерфейсом.
Дополнительные возможности Осени
- Алиасы и прозвища — группировка классов по функциональности (например, все команды имеют прозвище «Команда»)
- Компанейские желуди — создание новых экземпляров с параметрами (используется в ПарамертыДекомпилятора)
- Табакерка —Это, грубо говоря, получение желудя по требованию, иногда это полезно, например когда желудь нужен только при определенных условиях.
- Рогатка — точка входа в приложение
- Деталька — получение настроек из конфигурационного файла
- Завязь — для параметров конструктора, используется только с дубом
- Блестяшка — для произвольных аргументов конструктора
Тут можно зайти на основной репозиторий проекта
Напоследок хотелось сказать спасибо:
Владимиру Очаковскому за его мастер класс.
Овсянкину Андрею За Оскрипт
Никите Федькину за Осень
Александру за классный сервис Paste1c начинал делать бот я именно с него.
Чатам в телеграмме https://t.me/autumn_winow https://t.me/oscript_library
Вступайте в нашу телеграмм-группу Инфостарт