Чем хорош TRMNL — так это возможностью выводить что-то своё за считанные минуты.
С помощью «Private Plugins» можно взять ссылку, что отдаёт JSON (недавно добавили поддержку XML и сырого текста), рисуем простой шаблон на HTML с Liquid, готово! Для пущей динамики возможе неще и javascript, что позволяет выводить графики.
Можно опубликовать для других пользователей, можно брать опубликованное другими и либо использовать как есть — либо подправить под себя. Раздолье!
График сахара — пять минут, используя приведённый в документации шаблон графиков и два взмаха жаваскриптом для конвертации данных.
График шагов… А вот тут сложнее. Сервер позволяет простые GET и POST запросы, можно сунуть что-то в заголовки, URL, тело запроса и т.п. — но вот хранить состояние между запросами нельзя, то есть в лоб OAuth2 не реализуешь. Оно и понятно: они не очень хотят хранить данные авторизации для всех.
Что же делать?
Что ж. Решим задачу.
Дано:
-
есть платформа, которая может запрашивать урлы, но не хранит состояние;
-
есть источники данных, которые отдают по REST что попросишь — но требуют OAuth2 авторизации;
-
OAuth2 запросы авторизуется простыми ключами, но ключи требуют изначальной авторизации для выдачи прав, а потом постоянной ротации, чтоб поддерживать в актуальном состоянии;
-
нет желания поднимать и обслуживать виртуалку где бы то ни было;
-
нагрузка АЖ запрос раз в 15 минут. Может, если вдруг захочется, десяток запросов.
Решение:
-
берём бесплатный CloudFlare;
-
рисуем прокси, который будет проверять входящие запросы по статическому токену (без авторотации), и отсылать запросы дальше подписав динамическим токеном;
-
рисуем крон, который будет поддерживать динамические токены в актуальном состоянии.
Так как задача простая как пробка, что справится кто угодно, почему бы не попытаться заставить это сделать машину?
Так что дополнительное развлечение: будем вайбокодить.
Подготовка к решению
Устанавливаем курсор. Запускаем. Пытаемся «перенести» плагины — получается нерабочий ужас.
Сносим курсор, чистим, устанавливаем заново, говорим оставить только рекомендованные плагины. Пытаемся доставить нужные, не находим в маркете. Просто забиваем на это дело, «и так сойдёт» и будем ковыряться с деплоем вручную.
Активируем триальную лицензию (заодно узнаем, стоит ли за неё платить). Создаём новый Git репозиторий, устанавливаем nodejs и npm внутри wsl и на винде.
В общем и целом, часть команд он запускать может, интеграция с Wsl сломана, интеграция через ssh внутрь wsl работает но как-то косо. Я просто открыл папку проекта и держу открытый отдельный terminator, благо монитор достаточно широкий.
Всё, более-менее всё дышит, можно начинать вайбокодить.
Процесс решения
Попытка «в лоб» сформулировать задачу как бы я её задавал человеку оказалась катастрофически провальной, но это я знал заранее, так как уже игрался с сеточками для поиска решений.
Дао «заставить одну сеть составить план, который скармливать потом курсору» я не постиг: я сломался на попытке получить план, с которым я был бы согласен. Этот навык набивать можно будет позднее, перейдём к практике.
Кодить будем по шагам, и план простой: создать админку => добавить oauth авторизацию и хранение => добавить прокси => добавить ротацию => деплоим.
Часть первая: админка
(1) Говорим агенту, что мы пишем под CloudFlare workers на Javascript и просим создать скелет c двумя endpoint’ами: для настройки и для админки, админке нужен логин-пароль который хранится в KV базе.
Он создаёт какой-то код, который оч похож на правду. Восторгаемся пассажу про
<div class="credentials-info"> <p>Development credentials:</p> <p>Username: admin</p> <p>Password: password123</p> </div>
Но игнорируем, так как нигде внутри кода это не захардкожено.
Спрашиваем как его запустить для пощупать (я ничего не знаю про CloudFlare), его ответ не работает (wrangler в лоб не запускается ни на винде ни в wsl), вопрос в gemini объяснил недостающее, ставлю пакеты, через npx wrangler dev запускаю, не работает копируют ошибку про KV курсору, он прави тnamespace на local, оно запускается.
Прошу создать .gitignore, он его создаёт, и вроде даже похоже на правду. Коммитим, первый шаг готов.
(2) Просим в админке создать форму создания нового приложения и список приложений, в котором есть кнопка удалить и отредактировать. Для каждого приложения задаются его название, client id, пути для авторизации и API. Client ID и название редактировать нельзя, пути — можно.
Тут я познакомился с его подходом «простите, что-то не получилось, я сейчас еще раз». Раза с третьего он смог интегрировать своё решение в редактор. Выглядит так, что он иногда пытается сгенерировать дифф, а иногда полный файл.
В любом случае, он создал нечто, от чего я был в полном восторге: он добавил управление сессией! Сам !После проверки логина и пароля, он создал сессию и больше не надо вводить пароль, всё работает!
Очень внимательно полюбуйтесь на это. Пароль больше не надо вводить, да. Нужен только логин, который сохраняется в куку, очень удобно.
Просим переделать на использование рандомной куки, которая будет жить минут 15. Переделывает.
Спрашиваем «а не может ли KV проверять срок жизни?»… Может, говорит, и переделывает.
Уф, теперь ничего сходу страшного не обнаруживается, коммитим.
Часть вторая: oauth хранение и авторизация
(3) Пришла пора проверить его догадливость. Просим для каждого приложения добавить кнопку oauth авторизации, которую сохранять в базе приложения.
И он справляется! Сам добавляет хранение токенов, отдельный endpoint для callback’а при авторизации, генератор рандомного кода для верификации, причем реюзнул тот же что для сессий сделал на прошлом шаге. Ручные эксперименты с fitbit web api потребовали только прописать scope не «read write» а «activity».
Вот только редиректы — не работают. Несколько жалоб с копированием ошибки таки привели к кое-как рабочему решению.
Коммитим, пока не поломалось.
(4) Просим сделать scope параметром для приложения. Коммитим.
(5) Так как сервера часто проверяют callback url и требуют его ввести при настройке, просим вывести его на форму.
Он выводит и добавляет, как он сам сказал, для удобства, кнопочку копирования. Коммитим.
(6) Просим для приложений добавить уникальные прокси токены, с возможностью перегенерировать их если вдруг захочется — и вывести их для каждого приложения. Коммитим.
Часть третья: прокси
(7) Добрались до второй части нашего балета: GET прокси. Просим сделать так, чтоб /get/ эндпоинт брал первое слово после /get/ как имя приложения, а всё что дальше — использовал как путь для API. Проверял, что в запросе передали правильный proxyToken и если да — добавлял остаток ссылки у API адресу и пересылал подписав текущим OAuth ключом.
Неплохо справляется с первого раза. Вторым запросом просим сохранить любые GET параметры запроса (кроме proxyToken). Коммитим.
// Construct the target URL with all query parameters except proxyToken const targetUrl = new URL(path, app.apiPath); // Copy all query parameters except proxyToken for (const [key, value] of url.searchParams.entries()) { if (key !== 'proxyToken') { targetUrl.searchParams.set(key, value); } }
(Неплохо же для первого раза в жизни?)
Часть четвертая: свежевание ключей
(8) В смысле — просим создать workflow, который будет рефрешить ключи для всех приложений, у которых осталось меньше 3х часов свежести. И добавить крон, который раз в 2 часа будет запускать воркфлоу.
Он создаёт новый файл с новым кодом, который на мой неопытный глаз вообще выглядит не так, как документация говорит. Даём ему ссылку на документацию и просим сделать согласно актуальной спеки. Он переделывает, код похож, а вот техническая обёртка вокруг — нет. Просим еще раз переделать, сложив всё вместе. Переделывает, поломав и новый и старый код. А я не коммитил! К счастью, после известной истории, «откатить текущий шаг» доступен после каждой рекомендации (причем иногда при редактировании запроса — срабатывает, так как какой-то из хоткеев редактирования текста работает как «отменить всё»). Откатываем, сливаем файлы вручную. Просим еще раз привести к актуальному виду (дав ссылку). Приводит, поломав всего ничего по дороге. Чиним вручную.
Вручную локальный код работает, workflow локально тестировать невозможно. Фиг с ним, код на первый взгляд делает что просили — коммитим.
Часть пятая: деплоим и тестим на «проде»
(9) Поскольку нельзя нормально Workflow протестировать локально, несмотря на то, что документация говорит обратное (о чем разные сетки врут по-разному: те, что умеют искать в гугле — находят что нельзя, те, что не умеют — как только ни галлюцинируют) — деплоим.
Спрашиваем как, пробуем, не работает, гуглим, находим, побеждаем. Обновляем вранглер, просим еще раз обновить код (ранее вручную смерженный в один файл) согласно последней документации (даём ссылку на неё) и еще раз полируем после него вручную (он запутался выдал смесь TypeScript и JavaScript).
Просим как быть с реквизитами (созданные для key-value), после трёх итераций сдаёмся, нагугливаем ответ.
(Ответ, кстати, мне не нравится: надо wrangler.toml внести в .gitignore, и положить пример под другим именем. То есть мержить и держить их в актуальном состоянии — боль — но неважно, это делается на «раз поставил и забыл».)
Окей, как только деплой прошел на ура и приложение ожило — обновляем инструкции и коммитим.
Часть шестая: причесываем
(10) Первое, что бросилось в глаза на тестах: в процессе авторизации приложения слетает сессия админки. Курсор сломался решить проблему: предлагал пучок разных решений, но так и не догадался, что проблема в secure cookie, которые он сам же и проставил с самого начала. Но даже когда я ему объяснил в чем дело — не понял. Пришлось прямо сказать чтоб воткнул в середине процесса восстановление куки и редирект через HTML (то есть не через 302 Location а через 200 + meta-refresh). В процессе хоть вспомнил зачем HTML редирект делался :))).
(11) Пароли плейнтекстом.
Нет, я всё понимаю, но не надо так. Попросил его. Без обиняков. Просто, мол, сделай пароли солёными.
Он решил пойти простым путём, и если есть логин но нет пароля — первое же использование задаёт пароль. Что примечательно: он сам догадался поправить README, но форму, которая говорит про password123 не стал менять. А я тем более не буду: не барское это дело! Я уже за ним вручную линтеры прогонял и копипастил.
(12) Позже выяснилось, что если Fitbit пофиг, то вот Netatmo таки требует проверки clientSecret. Просим добавить clientSecret к приложениям — он добавляет. Просим пописать еще и к рефрешу. Добавляет, радуемся.
Что мы делаем? Выводы
Итого, за несколько присестов в выходные удалось создать желаемое: trmnl-oauth-proxy.
Приложение позволяет быстро развернуть на бесплатном cloudflare тарифе персональный oauth прокси, так что можно создавать и авторизовывать источники данных для своих нужд и легко выводить их в своём TRMNL терминале.
А что на счет вайб кодинга?
Задача решена? Да — плюс. Умеет читать документацию, если ему её показать. Тоже плюс.
Как средство решения задач — еще слишком юно. Требует постоянный глаз да глаз. Норовит пропустить что-то. Добавить от себя. Решить ну очень не правильным методом. Забывает, что попросили. Истории нет. Часто пытается перегенерировать всё заново, ломая по дороге то, что уже починил. Объём контекста ограничен. Путается в показаниях.
Короче очень юный джун. Но, к сожалению, джун, который не учится. Когда-нибудь, когда он станет лучше… Возможно. Но сейчас — нет. Работы по проверке за ним больше, чем экономия времени.
Основной плюс AI для программирования для себя: избавиться от чистого листа. Попросить скелет / набросок решения. Выкинуть потом оттуда всё и переписать под себя зачастую быстрее, чем пытаться совсем писать с нуля. Ну, так я уже могу — и тут курсор не единственное решение. Хоть они и были более-менее первыми — таки платить ему мне не за чем.
Но сколько сеток — столько мнений, так что у читателя может сложиться своё мнение. С удовольствием послушаю в комментария о другом личном опыте!
ссылка на оригинал статьи https://habr.com/ru/articles/900312/
Добавить комментарий