Я пытаюсь связать работника сервиса с клиентом в двух направлениях. Моя цель - делегировать обработку запроса клиенту и вернуться к работнику службы с правильным ответом. Последовательность шагов следующая:
Сервисный работник:
- Сервисный работник получает запрос
- Он проверяет, нужно ли его игнорировать или правильно управлять
- Создается сообщение с запросом и идентификатором корреляции
- Сообщение отправляется клиенту через входящее сообщение
- Пара {id: событие} зарегистрирована в хранилище сообщений.
Клиент:
- По входящему каналу приходит сообщение с запросом
- Сообщение деструктурируется для получения идентификатора корреляции и запроса
- Для запроса создается правильный ответ
- Идентификатор ответа и корреляции отправляется обратно работнику через исходящий канал
Работник службы:
- Ответное сообщение поступает по исходящему каналу
- Сообщение деструктурируется для получения идентификатора корреляции и ответа
- Ожидающее сообщение для этого идентификатора извлекается из хранилища сообщений
- Новый Объект ответа создается для ответа
- Объект ответа возвращается через
respondWith
Это мой работник службы:
const INSTALL = 'install'
const ACTIVE = 'activate'
const FETCH = 'fetch'
const MESSAGE = 'message'
const INSTALLED = 'Worker Installed'
const ACTIVATED = 'Worker Activated'
const FETCHING = 'Worker fetching'
const ICHANNEL = 'whale-ichannel'
const OCHANNEL = 'whale-ochannel'
const HEADERS = { 'Content-Type' : 'text/javascript' }
const PREFIX = '/whale/'
let toJson = JSON.stringify
let toJs = JSON.parse
let Messages = new Map ()
let idx = 0
let iChannel = new BroadcastChannel (ICHANNEL) // Incoming Channel
let oChannel = new BroadcastChannel (OCHANNEL) // Outgoing Channel
self.addEventListener (INSTALL, function (event) {
console.log (INSTALLED)
self.skipWaiting ()
})
self.addEventListener (ACTIVE, function (event) {
console.log (ACTIVATED)
event.waitUntil (clients.claim ())
oChannel.addEventListener (MESSAGE, function ({ data }) {
let id = data.id
let response = data.response
let message = Messages.get (id)
Messages.delete (id)
message.send (response)
})
})
self.addEventListener (FETCH, async function (event) {
if (isRequest (event)) await doRequest (event)
})
function isRequest (event) {
let { request } = event
let { url } = request
let uri = new URL (url)
let path = uri.pathname
let ok = path.startsWith (PREFIX)
return ok
}
function getRequest (event) {
let { request } = event
let { url } = request
let { referrer } = request
let headers = toJs (toJson (request)) || {}
return {
url,
referrer,
headers
}
}
function getResponse (data) {
let headers = HEADERS
let text = data
let response = new Response (text, { headers })
return response
}
function doRequest (event) {
let request = getRequest (event)
let {id, wait} = getMessage (event)
iChannel.postMessage ({ id, request })
return wait
}
function getMessage (event) {
let signal
let wait = new Promise (function (ok) { signal = ok })
let id = idx++
Messages.set (id, {
send : function (data) {
let response = getResponse (data)
event.respondWith (response) // [1]
signal (data)
}
})
return { id, wait }
}
Это мой клиент :
const ICHANNEL = 'whale-ichannel' // Incoming Channel
const OCHANNEL = 'whale-ochannel' // Outgoing Channel
// Register worker ...
let iChannel = new BroadcastChannel (ICHANNEL)
let oChannel = new BroadcastChannel (OCHANNEL)
iChannel.addEventListener (MESSAGE, async function ({ data }) {
let { id } = data
let { request } = data
let response = MyFancyResponse (...)
oChannel.postMessage ({
id,
response
})
})
При запуске этого кода выдается следующее сообщение об ошибке. См. [1] в коде сервисного работника. Обратите внимание, что весь коммуникационный поток выполняется правильно.
Uncaught DOMException: Failed to execute 'respondWith' on 'FetchEvent': The event handler is already finished.
Если я не пойму неправильно, это означает, что когда работник покидает клиент, чтобы найти клиентскую часть, событие извлечения завершается. Так что мой подход не действителен. У меня вопрос: как может быть реализована такая двусторонняя связь, когда процесс запрос-ответ разделяется по событиям сообщения?