У меня сейчас есть тема на одном сайте, которую я хотел бы иметь также на другом. Хотя я мог бы просто добавить гиперссылку, мне бы очень хотелось иметь возможность редактировать её на любом из сайтов, чтобы изменения отображались на обоих. Это избавит меня от необходимости поддерживать одну версию темы, которая быстро устаревает, и позволит держать обе темы постоянно актуальными. Кроме того, это даст мне возможность децентрализовать информацию со своего сайта.
Некоторые идеи по функциональности:
В качестве отправной точки один сайт остаётся хостом/владельцем темы, а остальные по сути её зеркалят. В дальнейшем даже интересно подумать, можно ли каким-то образом передать тему зеркальному сайту, если оригинал будет удалён.
Тема должна сохранять возможность быть скрытой, закрытой и т.п. на зеркальных сайтах.
Ответы не должны синхронизироваться — у каждого сайта своя аудитория, поэтому я не вижу, как можно было бы синхронизировать ответы.
Я понимаю, что реализация такой функции далеко не проста, но мне интересно, рассматривалось ли это ранее и какие уже есть результаты или эксперименты?
Не могли бы вы привести немного больше информации по этому поводу? С моей точки зрения, это, наоборот, уменьшит количество дублирующегося контента.
Создание резервных копий — не цель. Речь идет о создании единого источника истины для тем, которые уместны на нескольких сайтах.
Для наглядного примера: я занимаюсь оформлением визы. У меня есть тема в моем личном Discourse, которая по сути представляет собой чек-лист необходимых действий. Однако мои друзья тоже могут найти это полезным, поэтому я создаю такую же тему на нашем общем Discourse. Проблема в том, что мне нужно синхронизировать информацию в обеих темах отдельно, вместо того чтобы обновлять одну. Из-за этого часто в одной из тем не хватает ключевой информации.
Полагаю, это можно реализовать даже просто с помощью API-ключа для другого сайта? Возможно, что-то вроде кнопки или раздела в редакторе, где можно создать список API-ключей и URL-адресов для целевых тем. При внесении изменений в исходную тему вы могли бы нажать кнопку вроде «отправить изменения в клоны этой темы». Всё, что это сделает, — отправит обновление на темы в других инстансах.
Разместите информацию в одном единственном месте, где её сможет увидеть каждый. Ссылка — это способ сделать это.
Но у вас есть секретная информация, которую вы хотите сделать доступной в другом месте. Это уже другая история. Это вполне реализуемо с помощью плагина. Это тот тип проблемы, когда надуманное решение требует в 10 раз больше работы, чем сама проблема. (Я, например, часто трачу часы на автоматизацию задачи, которая должна выполняться лишь один раз.)
Но тогда вам нужно разместить его в таком месте, где он будет доступен только пользователю, который его опубликовал. Или сделать это общедоступным для всего сайта?
Снова же, они должны быть привязаны к каждому пользователю и обрабатываться в сериализаторе только для текущего пользователя (или, возможно, хранить их в профиле пользователя?). И вам потребуется структура данных для сопоставления API-ключей с различными сайтами. Похоже на задачу, которую, как мне кажется, я мог бы решить за 2–5 часов.
Таким образом, вам где-то нужно хранить URL-адреса для других сайтов, которые должны содержать эту тему. Создание такого поста тоже может быть сложным; самый простой способ — создать его вручную и включить URL этой темы с исходного сайта. Вероятно, это можно хранить в сыром тексте поста в виде какого-то BB-кода или чего-то подобного. Это позволит создать компонент, который сгенерирует кнопку и ссылку для каждого из них, а затем у вас будет код на Rails, который поставит в очередь задачу для отправки этого на другой сайт (сайты). Но принимающим сайтам не понадобится никакого кода — вы можете использовать API, чтобы отправить редактирование поста.
Похоже на задачу, которую, как мне кажется, я мог бы решить за 5–10 часов, но на деле это, скорее всего, займет в два раза больше времени. Если это для вас интересно, то это может стать крутым проектом.
Это также можно реализовать с помощью небольшого внешнего приложения, которое будет отслеживать вебхуки, отправляемые при редактировании на вашем исходном сайте, а затем использовать API для публикации на зеркальном сайте.
Плагин мог бы добавить пользовательское поле темы для URL-адреса источника основного документа. (Полагаю, также потребовались бы поля для удалённого имени пользователя и API-ключа, если основной документ должен быть скрыт, как, кажется, требуется в вашем случае, но эту часть можно отложить. Или, возможно, они могли бы находиться в пользовательском поле профиля. Ответственность за обеспечение того, чтобы API-ключ имел права только на чтение, лежала бы на том, кто его создал).
При создании темы вы вводили бы что-то вроде «remote: https://meta.discourse.org/t/synchronising-crossposting-topics-across-different-discourse-sites/263269», и при создании темы Discourse извлекал бы исходный текст удалённой темы, вставлял его в поле raw как правку и создавал запись в topic_custom_field с удалённым URL, возможно, добавляя вверху фразу «скопировано с url».
На этом этапе вы скопировали удалённую тему локально и сохранили запись о ней.
Затем могла бы появиться кнопка «Проверить источник», которая извлекала бы удалённую тему и сохраняла значение updated_at удалённой темы, а возможно, и её raw, в других пользовательских полях (это также мог бы делать фоновый процесс периодически, что немного улучшило бы UX). Затем можно было бы добавить кнопку «Обновить», которая заменяла бы существующее поле raw на удалённое, оформляя это как правку.
Если основной сайт общедоступен, то эта часть реализуется очень легко. Добавление API-ключа для доступа к приватному сайту усложняет задачу, а управление набором API-ключей на нескольких сайтах — ещё больше. Если нужно было бы заменить первоисточник, возможно, это можно было бы сделать с помощью задачи remap в rake, или добавить возможность редактирования пользовательского поля с удалённым URL при необходимости.
Эта часть предоставляется автоматически, поскольку в данном решении вторичные сайты извлекают данные с основного.
Эта мысль давно у меня в голове, но до недавнего времени она почти не развивалась. К сожалению, синхронизация между Discourse и Discourse потеряла для меня актуальность (речь шла лишь о нескольких темах), однако возросла потребность в общей синхронизации Markdown-файлов с других платформ.
Нашим основным сценарием использования в компании было размещение README-файлов и вики-страниц из проектов GitLab внутри Discourse (для обратной связи и поиска), при этом файлы в GitLab оставались единственным источником истины. Из-за отсутствия знаний Ruby я написал скрипт на Python, который, безусловно, избыточен по своей реализации, но вполне удовлетворителен по функционалу. Первая рабочая версия уже реализует часть того, что ты описал. Вот некоторые возможности:
содержит ссылку на оригинальный источник (файл в GitLab);
содержит ссылку на конкретную ревизию (номер коммита в GitLab);
обрабатывает изображения и ссылки на изображения:
загружает изображения из репозитория GitLab;
выгружает их в Discourse;
заменяет исходный URL изображения на короткую ссылку на загруженный файл;
добавляет тег “synced_with_gitlab”, чтобы их было легко найти.
Это работало примерно так же и с GitHub. У обеих платформ довольно схожий стиль Markdown, что делает процесс очень удобным.
Я бы с радостью сделал этот проект открытым, но сначала мне нужно уточнить юридические аспекты. Кроме того, текущая реализация на Python всё ещё выглядит немного кривой. В планах — переписать это в виде плагина на Ruby, но мне нужно будет посмотреть, смогу ли я найти на это время.
Не кажется ли это безумным и излишне усложнённым? Часть меня хочет создать для этого полноценное решение, что потребует учёта обоих вариантов — вебхуков и опроса.
Также я буду очень признателен за предложения по обеспечению безопасности содержимого базы данных. Сейчас я думаю о шифровании базы данных с помощью парольной фразы, которая должна быть передана в качестве аргумента при запуске скрипта, например:
discourse-sync run password123
В качестве небольшого вдохновения: вебхук может работать очень быстро:
Здесь показаны две темы на двух разных экземплярах. Тема слева — исходная, тема справа — целевая.
Теоретически согласен, но корпоративный мир всё усложняет:
Вебхуки в нашей компании невозможны из-за политик ИТ-безопасности (мы размещены за пределами компании через CDCK, и настройка проброса портов наружу требует сложных процедур) — поэтому работа через API обязательна.
Вебхуки быстры, удобны и идеально подходят для всех остальных, поэтому имеет смысл поддерживать и их тоже
Так что я уже реализовал грубую версию этого решения некоторое время назад. Работает отлично, но не масштабируемо. Плохой дизайн с моей стороны: я экспериментировал с идеей использовать тему с таблицей Markdown в качестве входных данных. Отлично работает, пока записей немного, но при 30+ записях всё превращается в кашу.
Один из сценариев использования Discourse-to-Discourse, который я вижу, — это единый источник истины для документации (Meta), синхронизирующийся с соответствующими постами на других инстансах. Это означает, что если команда изменит Core и обновит документацию пользователя в Meta, у меня будет актуальная версия этой документации на моём инстансе, доступная всем пользователям.
Для версии 2 я планирую использовать базу данных SQLite в качестве входных данных, как указано выше, и, вероятно, писать на Rust вместо Python.
Ниже приведён примерный набросок схемы.
graph TB
A[terminal] -- ~>discourse-sync run $PASSWORD --> B[Rust Script]
B -- SQLCipher:Decrypt DB using Password --> C[( sqlite: sources-and-targets')]
C -- 'Discourse' Table Data --> B
B -.- D{Decision on Type}
D -- Webhook --> E[Listen for Webhook Info]
D -- Polling --> F[Polling API]
E --> G[Receive New Information]
F --> G
G --> H[Parse and Process Data]
H --> I[POST\n tgt_domain, tgt_usr, tgt_key, post_id]
I --'raw' and images--> J[ Target Post ]
subgraph Rust Script Operations
B
D
E
F
G
H
I
end
Буду очень рад получить обратную связь и предложения по этому решению
Да, плагин ActivityPub теперь действительно поддерживает эту функцию. Мы очень близки к тому, чтобы начать использовать его internally для синхронизации документации между meta и внутренним экземпляром; это, кстати, включено в мой список задач на следующую неделю.
Это действительно относится к приватным экземплярам. В текущей версии плагина ActivityPub приватные экземпляры могут подписываться на категории в публичных экземплярах Discourse и, следовательно, получать опубликованную активность из этих экземпляров. (Однако контент в приватном экземпляре не публикуется, поэтому синхронизация осуществляется только в одном направлении: из публичного в приватный.)
Получается, что ActivityPub может работать следующим образом:
Публичный → Публичный
Публичный → Приватный
Приватный → Публичный
Приватный → Приватный
Это, безусловно, полезно во многих случаях, например, для трансляции документации от Meta. К сожалению, это пока не покрывает один из моих сценариев использования: публикацию с приватного экземпляра на другой приватный экземпляр. Судя по тому, что я нашёл, правильно ли я понимаю, что плагин ActivityPub вряд ли будет поддерживать такие сценарии в будущем? Мне кажется, что ActivityPub был разработан с расчётом на взаимодействие «публичный — публичный».
@Tris20, интересно! Спасибо, что поделились своими мыслями и некоторыми деталями по этому поводу.
То, что вы описали, — это одна из проблем, для решения которых и был создан ActivityPub. Не хочу слишком сильно охлаждать ваш энтузиазм, но, честно говоря, вам предстоит столкнуться с широким спектром задач, пытаясь реализовать это так, как вы описываете. Я не буду приводить исчерпывающий перечень всех препятствий, с которыми вам придётся справиться, но чтобы дать представление: плагин ActivityPub уже содержит почти 700 тестов rspec, и после года разработки он лишь недавно получил полноценную поддержку синхронизации тем между темами.
Я не вижу никаких внутренних ограничений на поддержку публикации «частный — публичный» и «частный — частный» через ActivityPub. Вопрос заключается в обеспечении соблюдения требований безопасности и контроля доступа при работе с частными экземплярами.
Позвольте предложить вам кое-что. Возможно, стоит подумать, как можно опираться на работу, уже проделанную плагином ActivityPub (и самим стандартом ActivityPub) в этом направлении. На самом деле уже существует решение для синхронизации контента между экземплярами Discourse, которое работает на данный момент. Оно пока не покрывает ваш сценарий, но решает большинство проблем, которые вам нужно будет преодолеть для достижения ваших целей.
Возможно, стоит поразмыслить о том, как может быть реализована синхронизация «частный — частный» в плагине, то есть как могут быть решены вопросы доступа и безопасности? Тогда, возможно, мы сможем вместе поработать над запросом на слияние (PR), чтобы добавить эту функцию. Может быть, вы дойдёте до точки, когда поймёте, что реализовать желаемое в контексте плагина (или стандарта ActivityPub) невозможно, но работа, проделанная вами для достижения этой точки, будет по сути такой же, как и для независимого решения, так что она не пропадёт даром.
В мире ActivityPub много умных людей, и меня бы не удивило, если бы подобная проблема (то есть публикация из частных источников) уже была глубоко рассмотрена ранее. Одним из мест, где можно найти соответствующие наработки, является SocialHub — основной форум сообщества ActivityPub (естественно, на платформе Discourse), который сейчас использует плагин Discourse ActivityPub