Socket.io испускает экспресс-маршрут для конкретного пользователя =

У меня есть экспресс-сервер, настроенный следующим образом для загрузки торрентов:

Сторона сервера

const WebTorrent = require('webtorrent')
const client = new WebTorrent()
const express = require('express')
const app = express()
const port = 3001
const http = require('http')
const server = http.createServer(app)
const { Server } = require("socket.io");
const io = new Server(server, {
    cors: {
        origin: "http://localhost:3000"
    }
});
app.io = io

//emitting works fine, but if more than one user sends a request to this endpoint, everyone gets all messages
app.get('/test', (req, res) => {
   const link = req.query.magnetlink
   req.app.io.emit('started', true)
   client.add(link, (torrent) => {
       const name = torrent.name
       req.app.io.emit('started', true)
       torrent.on('download, () => {
           req.app.io.emit('data', () => {
                name: name,
           })
       })
       torrent.on('done', () => {
           req.app.io.emit('done', () => {
                name: name
           })
       })
   })
})
server.listen(port, () => {
  console.info(`Running on http://localhost:${port}`)
})

Реагировать на стороне клиента

import * as React from 'react';
React.useEffect(() => {
   socket.on('started', (data) => {
       console.info(data)
       //do something here
   })
   socket.on('data', (data) => {
      console.info(data)
      //do something here
   })
}, [])

Пост , из которого я получил базовый код, почти 7-летней давности, и в нем не так много информации о том, как это сделать, как и в документации socket.io, в которой тоже нет никакой хорошей информации по этому поводу.

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

Вторая проблема заключается в том, что, используя этот метод, я не могу определить, подключен ли пользователь к маршруту. Если они все еще подключены, я хочу продолжить отправку данных, а если нет, я хочу убить процесс, который сервер выполняет для извлечения и отправки этих данных. Даже отправка на сервер внутри одного из «socket.on» никогда не будет получена сервером. Как мне проверить, подключен ли клиент, чтобы не тратить пропускную способность или дисковое пространство? Я не могу использовать io.on('connect') внутри маршрута, потому что я использую его в другом месте, чтобы проверить, находится ли пользователь в сети, и подсчитать, сколько пользователей находится в сети. Я просто хочу знать, подключен ли пользователь к маршруту /test. Опять же, излучение работает нормально. Я также хочу, чтобы сообщения отправлялись только этому конкретному пользователю, подключенному к маршруту /test, ПОКА они подключены к маршруту /test. Если пользователь обновляет свою страницу или отменяет ее, я хочу остановить передачу данных на стороне сервера, который делает что-то самостоятельно.

Проблема № 1 — поместить setInterval() внутри обработчика маршрута. Это означает, что каждый раз, когда вы попадаете на маршрут /test, вы запускаете ДРУГОЙ setInterval(), и они будут накапливаться и работать вечно.

jfriend00 18.04.2023 02:14

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

Wamy-Dev 18.04.2023 02:19

Можете ли вы показать нам настоящий код, пожалуйста? Что вызывает выброс и из какого контекста он запускается? Что значит "из трубы" в вашем комментарии? Пожалуйста, покажите настоящий код, а не придуманный код.

jfriend00 18.04.2023 02:23

Хорошо, я добавил реальный код. Я использую webtorrent для получения данных и предоставления информации о торренте. Не сами данные торрента.

Wamy-Dev 18.04.2023 02:54

У вас есть код, который отменяет эффект client.add()? Нравится client.remove()? Помните, что, в отличие от веб-страницы, серверы — это длительные процессы, поэтому вам нужно очищать все, что вы создаете от имени клиента.

jfriend00 18.04.2023 04:03

Таким образом, клиент НИКОГДА не подключается к маршруту. Клиент запрашивает маршрут, а затем, как только вы отправляете ответ, этот запрос полностью выполняется. Клиент может подключиться к вашему серверу через webSocket или socket.io. Если это так, то вам следует просто реализовать всю свою логику в сообщениях socket.io, а НЕ в экспресс-обработчиках маршрутов. Если клиент хочет сделать что-то, что получает ответ через socket.io, то просто сделайте этот запрос через сообщение socket.io, и тогда вы точно будете знать, на какое соединение socket.io отправить ответ обратно.

jfriend00 18.04.2023 04:05

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

jfriend00 18.04.2023 04:06

Если обработчик экспресс-запроса предоставляет веб-страницу, то соединение socket.io еще не будет установлено, когда будет отправлен ответ веб-страницы, поэтому соединения еще нет. Если обработчик экспресс-запроса является вызовом ajax с уже загруженной веб-страницы, то не делайте запрос через вызов ajax, сделайте его через сообщение socket.io, а затем тривиально узнать, на какой сокет отправить ответ.

jfriend00 18.04.2023 04:08

И если вы свяжете время жизни связанных с клиентом вещей, таких как client.add(), с временем жизни соединения socket.io, тогда все будет очищаться автоматически, когда это необходимо, поскольку вы можете просто вызвать client.remove(), когда соединение socket.io отключается.

jfriend00 18.04.2023 04:09

да, есть "torrent.on("done"), когда торрент закачивается, он отправляется пользователю в виде файла, я просто забыл его включить

Wamy-Dev 18.04.2023 06:00
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
10
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Это потому что ты делаешь io.emit(). Это транслируется на всех подключенных клиентов. Вам нужно сделать socket.emit() для конкретного сокета, на который вы хотите отправить.

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

Использование никогда не связано с маршрутом. Экспресс-маршрут — вещь временная. Какой-то клиент делает http-запрос к маршруту. Ответ отправляется. HTTP-запрос/маршрут завершен. Нет связи с маршрутом.

Клиент может установить соединение socket.io с сервером. Это создает непрерывное соединение между клиентом и сервером, которое НИЧЕГО не имеет общего с конкретным маршрутом. Это соединение между этим конкретным клиентом и сервером.

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

Я не знаю вашего торрент-кода, но общая структура будет такой:

// client sends socket.io getDownload message with {url: xxx} as the data to 
// initiate your torrent code

// server-side code
io.on('connection', socket => {
    socket.on('getDownload', data => {
        const url = data.url;
        client.add(url, (torrent) => {
            const name = torrent.name
            socket.emit('started', true);

            // other torrent code here
            // you can use socket.emit() here to send to this particular socket
            // When torrent is done, make sure to do client.remove() to clean up

        });
    });
    socket.on('disconnect', () => {
        // clean up any torrent stuff on behalf of this client
    });
});

Не инициируйте свой торрент-файл с URL-адресом http, потому что вы не знаете, какое соединение socket.io принадлежит этому клиенту, отправляющему этот http-запрос, или есть ли оно еще.

Это нельзя использовать, так как я должен использовать маршрут, чтобы он был защищен моей проверкой приложения firebase. Каждый маршрут должен быть защищен, так как у меня нет аутентификации. Мой вопрос связан с маршрутами. Я бы сделал это, если бы мне было нужно, но я не могу.

Wamy-Dev 18.04.2023 16:21

@Wamy-Dev - Ну, НИ ОДНОГО из этих требований не входит в вопрос, поэтому я предложил лучший способ сделать что-то с учетом предоставленной информации. Все ваше представление о том, что вы «подключены» к маршруту, просто неверно, поэтому вам придется все переосмыслить. Клиент подключен к серверу, а не к маршруту.

jfriend00 18.04.2023 22:43
Ответ принят как подходящий

Я придумал собственное решение. Шаги следующие:

  1. Сначала я отправил запрос на сервер в /handshake, который проверил пользователя с помощью аутентификации и других промежуточных программ. Это вернет OK, если пользователь может загрузить, если нет, то отправит любую ошибку (403, 500 и т. д.).
  2. Как только клиент получил рукопожатие, я отправил сигнал «загрузки» на socket.io со всеми необходимыми параметрами загрузки.
  3. Когда файл загружается на сервер, пользователь будет получать обновления статуса от «on.('download')» из торрента.
  4. Если в любой момент клиент отключается, загрузка прерывается, а файлы удаляются.
  5. Как только загрузка завершена, она архивируется, и клиенту передается сигнал «torrentDone» с информацией о файле, чтобы пользователь мог найти ее позже.
  6. Затем, когда пользователь готов, он просто отправляет запрос на сервер, используя обычную экспресс-конечную точку, и файл обслуживается, а затем удаляется на сервере.

Спасибо за помощь.

Другие вопросы по теме