Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RestServer and Socket.io #4496

Closed
TheZwieback opened this issue Jan 24, 2020 · 6 comments
Closed

RestServer and Socket.io #4496

TheZwieback opened this issue Jan 24, 2020 · 6 comments
Labels

Comments

@TheZwieback
Copy link

Hi,

I want to implement a WebSocket server on a loopback rest server. As the rest server is based on an express app with a node http server this should be straight forward. Unfortunately I found a minor issue. Accessing the node http server object is not possible in the RestApplication constructor as it is protected inside the RestServer class. I changed the properties on my machine locally and tested the standard deployment and it works as expected:

import { BootMixin } from '@loopback/boot';
import { ApplicationConfig } from '@loopback/core';
import {
  RestExplorerBindings,
  RestExplorerComponent,
} from '@loopback/rest-explorer';
import { RepositoryMixin } from '@loopback/repository';
import { RestApplication } from '@loopback/rest';
import { ServiceMixin } from '@loopback/service-proxy';
import * as path from 'path';
import { MySequence } from './sequence';
import { Server as ioServer, ServerOptions as ioServerOptions, Socket } from "socket.io";
import SocketIOServer = require('socket.io');

export class Bff extends BootMixin(
  ServiceMixin(RepositoryMixin(RestApplication)),
) {
  private ioServer: ioServer;

  constructor(options: ApplicationConfig = {}) {
    super(options);

    // Set up the custom sequence
    this.sequence(MySequence);

    // Set up default home page
    this.static('/', path.join(__dirname, '../public'));

    // Customize @loopback/rest-explorer configuration here
    this.bind(RestExplorerBindings.CONFIG).to({
      path: '/explorer',
    });
    this.component(RestExplorerComponent);

    this.projectRoot = __dirname;
    // Customize @loopback/boot Booter Conventions here
    this.bootOptions = {
      controllers: {
        // Customize ControllerBooter Conventions here
        dirs: ['controllers'],
        extensions: ['.controller.js'],
        nested: true,
      },
    };

    this.ioServer = SocketIOServer();
  }

  async start(): Promise<void> {
    await super.start();
    console.log(this.restServer.listening);
    this.ioServer.attach(this.restServer._httpServer!.server);
    console.log(this.ioServer);
  }
}

Would it be possible to make the base http Server object (this.restServer._httpServer) available through a getter? Using the RestServer instance in the ioServer.attach method does not work.

Thanks and cheers,
Christian

@raymondfeng
Copy link
Contributor

raymondfeng commented Jan 24, 2020

@TheZwieback
Copy link
Author

TheZwieback commented Jan 25, 2020

@raymondfeng I looked at the package and it seems to instantiate a new http server to use in its middleware. It would be nice to just use an existing one, i.e. like the rest server described above.
I do not need to expose the socket.io server through dedicated controller endpoints, instead I want the regular http rest endpoints to deliver progress updates through socket.io.
Maybe a mixin would be possible to enhance the RestServer cleanly?

@gemyero
Copy link

gemyero commented Jun 27, 2020

@TheZwieback I write some code to solve this problem. I write a mixin called RevealServerMixin which can be invoked with RestApplication class and it do it. Here is the code.

// RevealServerMixin
import { Constructor } from '@loopback/core';
import { CustomRestComponent } from '../services/CustomRestComponent';
import { CustomRestServer } from '../services/CustomRestServer';


export function RevealServerMixin<T extends Constructor<any>>(
  BaseClass: T,
) {
  class Subclass extends BaseClass {
    constructor(...args: any[]) {
      super(...args);

      this.unbind('components.RestComponent');
      this.unbind('servers.RestServer');

      this.component(CustomRestComponent);
    }

    get restServer(): CustomRestServer {
      return this.getSync('servers.CustomRestServer');
    }
  }
  return Subclass;
}
// CustomRestComponent
import { RestComponent } from '@loopback/rest';
import { Constructor, Server } from '@loopback/core';
import { CustomRestServer } from './CustomRestServer';

export class CustomRestComponent extends RestComponent {
  servers: {
    [name: string]: Constructor<Server>
  } = {
    CustomRestServer,
  };
}
// CustomRestServer
import { RestServer } from '@loopback/rest';
import { HttpServer } from '@loopback/http-server';

export class CustomRestServer extends RestServer {
  get httpServer(): HttpServer | undefined {
    return this._httpServer;
  }
}

And in application.ts

export class MyApplication extends RevealServerMixin(RestApplication)
) {}

@alexkander
Copy link
Contributor

Maybe this can help #4044

@stale
Copy link

stale bot commented Jul 14, 2021

This issue has been marked stale because it has not seen activity within six months. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository. This issue will be closed within 30 days of being stale.

@stale stale bot added the stale label Jul 14, 2021
@stale
Copy link

stale bot commented Aug 13, 2021

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.

@stale stale bot closed this as completed Aug 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants