Все, кто знаком с архитектурой Croquet, с нетерпением ждут (ожидают, затаив дыхание) обновления архитектуры Open Croquet от Croquet V Дэвида А. Смита и Croquet Studios. »!

Однако при работе над проектом LiveCoding.space от Крестьянство.org, который в значительной степени основан на Virtual World Framework (содержащем элементы архитектуры Open Croquet), я начал пересматривать текущий сервер Reflector.

Позвольте представить вам идеи и ранний прототип Krestianstvo Luminary для архитектуры Open Croquet и Virtual World Framework. Крестианство Luminary потенциально может заменить сервер Reflector в духе использования автономной Gun DB чистой распределенной системы хранения . Это позволяет вместо Отражения сообщений с централизованным временем Крокета теперь Сиять время на каждом подключенном узле с помощью Гипотетической машины амнезии Гана. >, работающий в одноранговой сети. Также для защиты всех внешних потоков сообщений с помощью одноранговых идентификаторов и криптографической библиотеки SEA для Gun DB. Более подробно о запуске Luminary на блокчейне AXE.

Крестианство Luminary просто преобразует единственную серверную часть Croquet — Reflector (взято из версии VWF) в чисто одноранговое приложение, работающее в веб-браузерах клиента.

Для тех, кто не знаком с архитектурой Open Croquet, просто хочу отметить ключевые принципы, стоящие за ней, простыми словами.

Крокет Архитектура

Крокет ввел понятие виртуального времени для децентрализованных вычислений. Думать об объектах как о потоке сообщений, что приводит к детерминированным вычислениям на каждом подключенном узле в децентрализованной сети. Все вычисления выполняются на каждом узле отдельно при интерпретации внутренней очереди сообщений, которые не реплицируются в сеть. Но эти очереди синхронизируются внешними пульсирующими сообщениями, поступающими от Reflector — крошечного сервера. Также любые самогенерируемые сообщения узла, которые должны распространяться на другие узлы, помечаются как внешние. Они явно перенаправляются к рефлектору, где теперь отмечаются временем рефлектора и возвращаются обратно на сам узел и все другие узлы в сети.

Reflector используется не только для отправки сообщений пульса, штамповки внешних сообщений, но также для хранения списка подключенных клиентов, списка запущенных экземпляров виртуального мира, начальной загрузки новых клиентских подключений.

Отражатель

Итак, в архитектуре Croquet для децентрализованных сетей Reflector, будучи очень маленьким или даже микросервисом, остается сервером. Он использует WebSockets для координации клиентов, мировых экземпляров, предоставления «текущего времени» для клиентов, отражения внешних сообщений.

Давайте посмотрим, как это работает в Virtual World Framework (VWF). Я буду использовать доступный открытый исходный код от VWF, который использую в проекте LiveCoding.space by Krestianstvo.org

Теперь функция Reflector возвращает время. Время считывается с машины, на которой запущен сервер Reflector: (код сервера из lib/reflector.js)

function GetNow( ) {
return new Date( ).getTime( ) / 1000.0;
}

Затем он использует для создания штампа для экземпляра виртуального мира:

return ( GetNow( ) — this.start_time ) * this.rate

Reflector отправляет эти временные метки с помощью WebSockets. А на стороне клиента у VWF есть метод диспетчеризации: (клиентский код из public/vwf.js)

socket.on( “message”, function( message ) {
var fields = message;
…
fields.time = Number( fields.time );
fields.origin = “reflector”;
queue.insert( fields, !fields.action );
…

Посмотрите на методы отправки и ответа, где клиенты используют WebSocket для отправки внешних сообщений обратно в Reflector:

var message = JSON.stringify( fields );
socket.send( message );

светило

Теперь давайте посмотрим, как Крестьянство Luminary может идентично заменить сервер Reflector.

Прежде всего, клиенты никогда не вынуждены использовать WebSockets непосредственно из самого приложения для отправки или получения сообщений. Вместо этого Gun DB отвечает за эту функциональность внутри компании. Все операции, которые ранее передавались через соединение WebSocket, заменены подпиской на обновления и изменения в узлах и свойствах Gun DB.

Итак, инстансы, клиенты — это просто узлы Gun DB, доступные всем подключенным пирам. В этой сцене требуемая логика приложения Reflector перемещается с сервера на клиентов. Так как каждый клиент в любой момент времени может получить актуальную информацию об экземпляре, к которому он подключен, клиентах в этом экземпляре и т. д. Просто запросите узел в Gun DB.

Теперь о времени.

Вместо new Date().getTime() машины Крестьянство Luminary использует состояние из Гипотетической машины амнезии Гана, которая сочетает в себе временные метки, векторные часы и разрешение конфликтов. алгоритм. Таким образом, каждое записанное свойство в узле Gun имеет отметку HAM. Это состояние одинаково для всех сверстников. Это означает, что мы можем получить это состояние только на любом клиенте.

Принимая во внимание, что Gun DB гарантирует, что каждое изменение на каждом узле или свойстве будет доставлено в правильном порядке всем одноранговым узлам. Мы могли бы создать узел сердцебиения и подписывать пиры на его обновления.

Вот код для создания сердцебиения для VWF:

Gun.chain.heartbeat = function (time, rate) {
// our gun instance
var gun = this;
gun.put({
    ‘start_time’: ‘start_time’,
    ‘rate’: 1
}).once(function (res) {
// function to start the timer
setInterval(function () {
    let message = {
    parameters: [],
    time: ‘tick’
};
gun.get(‘tick’).put(JSON.stringify(message))}, 50);
})
// return gun so we can chain other methods off of it
return gun;
}

Клиент, который запускается первым или создает новый экземпляр виртуального мира, создает узел сердцебиения для этого экземпляра и запускает метроном (эта часть может быть запущена в экземпляре Gun DB где-то на хост-сервере для доступности в любое время):

let instance = _LCSDB.get(vwf.namespace_); //
instance.get(‘heartbeat’).put({ tick: “{}” }).heartbeat(0.0, 1);

Таким образом, каждые 50 мс этот клиент будет записывать в свойство 'tick' содержимое сообщения, тем самым изменяя его, поэтому Gun HAM будет перемещать состояние для этого свойства, помечая его новым уникальным значением, из которого будет рассчитываться время Croquet. позже.

Время начала будет значением состояния HAM в свойстве start_time узла пульса. Обратите внимание, что фактическая метка времени Croquet здесь не рассчитывается, как это было на сервере Reflector. Отметка времени, используемая для внутренней очереди сообщений Croquet, будет рассчитываться при чтении «тика» клиентом VWF в его основном приложении.

Вот упрощенная базовая версия диспетчеризации «галочки» в главном клиентском приложении VWF, просто чтобы понять идею: (полный код на public/vwf.js, ссылки ниже)

let instance = _LCSDB.get(vwf.namespace_);
instance.get(‘heartbeat’).on(function (res) {
if(res.tick) {
let msg = self.stamp(res, start_time, rate);
queue.insert(fields, !fields.action);
     }
}
this.stamp = function(source, start_time, rate) {
let message = JSON.parse(source.tick);
message.state = Gun.state.is(source, ‘tick’);
message.start_time = start_time; //Gun.state.is(source, ‘start_time’);
message.rate = rate; //source.rate;
var time = ((message.state — message.start_time)*message.rate)/1000;
if (message.action == ‘setState’){
time = ((_app.reflector.setStateTime — message.start_time)*message.rate)/1000;
}
message.time = Number( time );
message.origin = “reflector”;
return message
}

Основным моментом здесь является расчет времени Крокета с использованием состояния HAM Gun:

Gun.state.is ( node, property )

для сообщения:

message.state = Gun.state.is(source, ‘tick’); // time of updating tick
message.start_time = Gun.state.is(source, ‘start_time’); //start time of the instance heartbeat
message.rate = source.rate;
var time = ((message.state — message.start_time)*message.rate)/1000;

Таким образом, все одноранговые узлы будут вычислять одинаковое время Croquet при получении обновления от Gun DB, независимо от времени, когда они получили это обновление (задержки в сети и т. д.).

Как вы могли себе представить, отправка внешних сообщений будет такой же простой, как просто запись сообщения одноранговым узлом в экземпляр Heartbeat с новым содержимым сообщения. Все подключенные одноранговые узлы и сам одноранговый узел получат это сообщение с отметкой времени Croquet, пока они подписаны на изменения на узле пульса (см. выше определение instance.get('heartbeat').on()). )

instance.get(‘heartbeat’).get(‘tick’).put(JSON.stringify(newMsg));

На самом деле это так!

Выводы

  • Сервер Reflector больше не требуется для запуска виртуальных миров (подойдет любой существующий экземпляр GunDB в сети, он может ничего не знать о Croquet и клиентах)
  • клиенты, экземпляры мира, логика подключения хранятся в распределенной БД
  • штампы сообщений делают сами клиенты с помощью Gun’s HAM
  • один выделенный одноранговый узел, производящий пустые сообщения метронома для продвижения вперед (может быть где угодно)

Все преимущества, которые предоставляет Gun DB, могут быть применимы в архитектуре Croquet. Одним из сценариев может быть использование Gun’s Timegraph. Это позволит сохранять и извлекать историю сообщений для записи и последующего воспроизведения. Использование библиотеки безопасности, шифрования и авторизации SEA позволит создать высокозащищенные пульсации экземпляра с использованием одноранговой идентификации и развертывания в любом месте и в любое время, доступном в блокчейне AX.

Проблемы

Для создания полнофункционального прототипа все еще существуют проблемы с переносом логики приложения Reflector на функционально-реактивную архитектуру Gun DB. Это касается процедуры подключения клиентов к работающему экземпляру. Поскольку это связано с получением/настройкой состояния экземпляра, ожидающими сообщениями и их последующим воспроизведением на новых подключенных узлах. Но все это не критично, так как не затрагивает основную идею Крестьянства Luminary.

Есть проблемы с производительностью, так как Gun DB использует адаптер хранилища RAD. Но может быть полезно настроить несколько параметров RAD, касающихся opt.chunk и opt.until (из-за времени анализа RAD или JSON для каждого фрагмента).

Исходный код

Необработанный код доступен в репозитории LiveCoding.space GitHub в ветке luminary.

Ветка luminary-partialсодержит рабочий прототип частичного Luminary, когда для логики рефлектора выбран один мастер-клиент, он использует Gun.state() для штамповки сообщений, как это было сделано в оригинальном приложении Reflector, а затем распространять в виде обновлений другим одноранговым узлам через Gun DB.

Спасибо за чтение, и я буду рад, если вы поделитесь своими комментариями и взглядами на это.

Николай Суслов

Копия оригинальной статьи по адресу: https://blog.krestianstvo.org/ru/krestianstvo-luminary-for-open-croquet-architecutre-and-virtual-world-framework-in-peer-to-peer-web/