В настоящее время у нас есть приложение VueJS
, и я планирую перенести его в Cycle.js (первый крупный проект).
Я понимаю, что в Cycle.JS у нас есть SI и SO для драйверов (с использованием adapt());Естественно, реализация WebSocket подходит для этого, поскольку имеет эффекты как чтения, так и записи.
Мы используем Phoenix (Elixir) в качестве нашего бэкенда, используя каналы для мягкой коммуникации в реальном времени.Наша клиентская библиотека WS - это Phoenix здесь https://www.npmjs.com/package/phoenix.
Пример на Cycle.js.org идеально подходит, если вы знаете, как подключиться.
В нашем случаемы аутентифицируемся, используя конечную точку REST, которая возвращает токен (JWT), который используется для инициализации WebSocket (параметр токена).Этот токен нельзя просто передать в драйвер, так как драйвер инициализируется при запуске приложения Cycle.js.
Пример (не фактический код) того, что мы имеем сейчас (в нашем приложении VueJS):
// Code ommited for brevity
socketHandler = new vueInstance.$phoenix.Socket(FQDN, {
_token: token
});
socketHandler.onOpen(() => VueBus.$emit('SOCKET_OPEN'));
//...... Vue component (example)
VueBus.$on('SOCKET_OPEN', function () {
let chan = VueStore.socketHandler.channel('PRIV_CHANNEL', {
_token: token
});
chan.join()
.receive('ok', () => {
//... code
})
})
Выше приведен пример, у нас есть хранилище Vuex
для глобального состояния (сокет и т. Д.), Централизованная шина сообщений (приложение Vue) для связи между компонентами и настройками канала, которые поступают из экземпляра Phoenix Socket..
Наша настройка канала основана на аутентифицированном соединении Socket, которому требуется сама аутентификация для подключения к этому конкретному каналу.
Вопрос в том, возможно ли это даже с Cycle.js?
- Инициализация соединения WebSocket с параметрами токена из вызова REST (ответ токена JWT) - мы реализовали это частично
- Создание каналов на основе этого сокета и токена ( канал)потоков из драйвера? )
- Доступ к нескольким канальным потокам ( Я предполагаю, что это может сработатьe sources.HTTP.select (CATEGORY) )
У нас есть зависимость 1: N, которая, я не уверен, возможна с драйверами.
Заранее спасибо,
Обновление @ 17/12/2018
По сути, я пытаюсь подражать следующему (из Cycle.js.org):
Драйвер принимает приемник для выполнения эффектов записи (отправки сообщений по определенным каналам), но также может возвращать источник;это означает, что есть два потока, которые являются асинхронными?Это означает, что создание сокета во время выполнения может привести к тому, что один поток получит доступ к «сокету» до его создания;пожалуйста, смотрите комментарии во фрагменте ниже.
import {adapt} from '@cycle/run/lib/adapt';
function makeSockDriver(peerId) {
// This socket may be created at an unknown period
//let socket = new Sock(peerId);
let socket = undefined;
// Sending is perfect
function sockDriver(sink$) {
sink$.addListener({
next: listener => {
sink$.addListener({
next: ({ channel, data }) => {
if(channel === 'OPEN_SOCKET' && socket === null) {
token = data;
// Initialising the socket
socket = new phoenix.Socket(FQDN, { token });
socketHandler.onOpen(() => listener.next({
channel: 'SOCKET_OPEN'
}));
} else {
if(channels[channel] === undefined) {
channels[channel] = new Channel(channel, { token });
}
channels[channel].join()
.receive('ok', () => {
sendData(data);
});
}
}
});
},
error: () => {},
complete: () => {},
});
const source$ = xs.create({
start: listener => {
sock.onReceive(function (msg) {
// There is no guarantee that "socket" is defined here, as this may fire before the socket is actually created
socket.on('some_event'); // undefined
// This works however because a call has been placed back onto the browser stack which probably gives the other blocking thread chance to write to the local stack variable "socket". But this is far from ideal
setTimeout(() => socket.on('some_event'));
});
},
stop: () => {},
});
return adapt(source$);
}
return sockDriver;
}
Ян ван Брюгге, предоставленный вами солютон идеален (спасибо), за исключением того, что у меня возникли проблемы с ответной частью.Пожалуйста, смотрите приведенный выше пример.
Например, я пытаюсь добиться чего-то вроде этого:
// login component
return {
DOM: ...
WS: xs.of({
channel: "OPEN_CHANNEL",
data: {
_token: 'Bearer 123'
}
})
}
//////////////////////////////////////
// Some authenticated component
// Intent
const intent$ = sources.WS.select(CHANNEL_NAME).startWith(null)
// Model
const model$ = intent$.map(resp => {
if (resp.some_response !== undefined) {
return {...}; // some model
}
return resp;
})
return {
DOM: model$.map(resp => {
// Use response from websocket to create UI of some sort
})
}