Отправленное сервером событие с Angular 7 + Loopback 3 - PullRequest
0 голосов
/ 28 февраля 2019

Я пытаюсь создать приложение в реальном времени, используя Angular 7 и Loopback SSE, как , описанное здесь , но я сталкиваюсь с двумя основными проблемами:

1) Я не смог установить аутентифицированное соединение .Обычно я делаю все http-запросы с токеном доступа в заголовке, но EventSource не имеет API для отправки HTTP-заголовков на сервер.Поэтому я пытаюсь добавить параметры "access_token" в URL и пытаюсь также использовать пакет ng-event-source , который дает возможность предоставлять собственные заголовки HTTP.В обоих случаях происходит сбой сервера с непонятным сообщением об ошибке "npm ERR! code ELIFECYCLE npm ERR! errno 1".

Чтобы избежать этой проблемы, я должен отключить ACL в моей модели.

2) Мне не удалось отправить пульс подключенным клиентам , и клиенты отключаются через X секунд.На самом деле EventSourcePolyfill является вилкой этого пакета , который требует, чтобы сервер отправлял сообщения каждые X секунд в качестве пульса для обнаружения отключений.

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

SERVER

/ server / models / my_model.js

{
  "name": "MyModel",
  "mixins": {
    "AccessControl": false
  },
 "acls": [
    {
      "accessType": "*",
      "principalType": "ROLE",
      "principalId": "$everyone",
      "permission": "DENY"
    },    
    {
      "property": "createChangeStream",
      "accessType": "READ",
      "principalType": "ROLE",      
      "principalId": "$everyone",
      "permission": "ALLOW"
    }

/ server / boot / realtime.js

const es = require('event-stream');
module.exports = function(app) {
  const myModel = app.models.MyModel;
  myModel .createChangeStream(function(err, changes) {    
    changes.pipe(es.stringify()).pipe(process.stdout);    
  });
}

CLIENT

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { EventSourcePolyfill } from 'ng-event-source';

@Injectable()
export class ServerEventService {
    protected apiServer = 'http://localhost:3000/';

    getReservationStream(): Observable<any> {
        return Observable.create((observer) => {            
            let eventSource = new EventSourcePolyfill (this.apiServer + 'api/MyModels/change-stream?_format=event-stream', { heartbeatTimeout: 5000, connectionTimeout: 5000});
            eventSource.addEventListener('data', function (event) {
                console.debug('Received event: ', event);
                let json = JSON.parse(event.data);
                observer.next(json);
            });
            eventSource.onerror = (error) => {
                // readyState === 0 (closed) means the remote source closed the connection
                if (eventSource.readyState === 0) {
                    console.log('The stream has been closed by the server.');
                    eventSource.close();
                    observer.complete();
                } else {
                    observer.error('EventSource error: ' + error);
                }
            }
        });
    }
}

Заранее спасибо.

ОБНОВЛЕНИЕ 09/03/2019

Мне удалось решить вторую проблему, добавив Middelware в / server / server.js :

app.middleware('routes:before', function (req, res, next) {
  if (req.path.indexOf('change-stream') !== -1) {
    setInterval(() => {
      let timestamp = +new Date();
      res.write("heartbeat " + timestamp);
    }, 20000);
  }
  next();
});
...