Skip to content

How to integrate socket in loopback 4 server API #4044

Closed

Description

@imranalisolanki

i want implement socket in my loopback4 server API. i have integrate socket in my API but it;s routing is not working.

app.io = require('socket.io')(await app.start());
  app.io.on('connection', async function (socket: any) {

    console.log('connected', socket.id)
    socket.on('disconnect', function () {
      console.log('user disconnected');
    });
  });

it's my code but socket is not connected. i have seen this example.

https://github.com/raymondfeng/loopback4-example-websocket/
but it's work only socket server not working with API server. please suggest me how i can implement.

Activity

  1. hacksparrow commented on Nov 4, 2019

    @hacksparrow
    Contributor

    Hi @imranalisolanki can you share a minimal version of your app reproducing the issue, so I can troubleshoot? Sharing a code snippet is not enough, since other factors responsible for the failure may be left out of the context.

  2. imranalisolanki commented on Nov 4, 2019

    @imranalisolanki
    Author

    @hacksparrow i have create a simple loopback4 server with some routing and i have gone through https://github.com/raymondfeng/loopback4-example-websocket/ this example and when i have configure it in my server then existing routing is not working.
    Application.ts
    import { BootMixin } from '@loopback/boot';
    import { ApplicationConfig, BindingKey } 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 { AuthenticationSequence } from './sequence';
    import { AuthenticationComponent, registerAuthenticationStrategy } from '@loopback/authentication';

    import { TokenServiceBindings, UserServiceBindings, TokenServiceConstants, PasswordHasherBindings, EmailServiceBindings, FCMServiceBindings, ControllerServiceBindings } from './keys';
    import { JWTService } from './services/jwt-service';
    import { MemberService } from './services/user-service';
    import { BcryptHasher } from './services/hash.password.bcryptjs';
    import { JWTAuthenticationStrategy } from './authentication-strategies/jwt-strategy';
    import { EmailService, FCMService, ControllerService } from './services';
    import { ReviewController } from './controllers';
    import { SECURITY_SCHEME_SPEC } from './utils/security-spec';

    export interface PackageInfo {
    name: string;
    version: string;
    description: string;
    }
    export const PackageKey = BindingKey.create('application.package');

    const pkg: PackageInfo = require('../package.json');

    export class BreezeApiApplication extends BootMixin(ServiceMixin(RepositoryMixin(RestApplication))) {
    constructor(options: ApplicationConfig = {}) {
    super(options);

    this.api({
      openapi: '3.0.0',
      info: { title: pkg.name, version: pkg.version },
      paths: {},
      components: { securitySchemes: SECURITY_SCHEME_SPEC },
      servers: [{ url: '/' }],
    })
    
    this.setUpBindings();
    
    // Bind authentication component related elements
    this.component(AuthenticationComponent);
    
    registerAuthenticationStrategy(this, JWTAuthenticationStrategy);
    
    // Set up the custom sequence
    this.sequence(AuthenticationSequence);
    
    // 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,
      },
    };
    

    }

    setUpBindings(): void {
    this.bind(TokenServiceBindings.TOKEN_SECRET).to(TokenServiceConstants.TOKEN_SECRET_VALUE);
    this.bind(TokenServiceBindings.TOKEN_EXPIRES_IN).to(TokenServiceConstants.TOKEN_EXPIRES_IN_VALUE);
    this.bind(TokenServiceBindings.TOKEN_SERVICE).toClass(JWTService);

    this.bind(PasswordHasherBindings.ROUNDS).to(10);
    this.bind(PasswordHasherBindings.PASSWORD_HASHER).toClass(BcryptHasher);
    
    this.bind(UserServiceBindings.USER_SERVICE).toClass(MemberService);
    this.bind(EmailServiceBindings.MAIL_SERVICE).toClass(EmailService)
    this.bind(FCMServiceBindings.FCM_SERVICE).toClass(FCMService);
    this.bind(ControllerServiceBindings.CONTROLLER_SERVICE).toClass(ControllerService);
    

    }
    }

    index.ts

    import { BreezeApiApplication } from './application';
    import { ApplicationConfig } from '@loopback/core';

    export { BreezeApiApplication };

    export async function main(options: ApplicationConfig = {}) {
    const app = new BreezeApiApplication(options);
    await app.boot();
    //await app.start();

    app.io = require('socket.io')(await app.start());
    app.io.on('connection', async function (socket: any) {

    console.log('connected', socket.id)
    socket.on('disconnect', function () {
      console.log('user disconnected');
    });
    

    });

    const url = app.restServer.url;
    console.log(Server is running at ${url});

    return app;
    }

  3. hacksparrow commented on Nov 4, 2019

    @hacksparrow
    Contributor

    @imranalisolanki the code you pasted refers to many files not found in the original https://github.com/raymondfeng/loopback4-example-websocket/. Also it has basic run-time errors like console.log(Server is running at ${url});.

    I will be able to help you if you can provide a minimal app reproducing the error. Code snippets are not enough.

  4. kchraniuk commented on Nov 5, 2019

    @kchraniuk

    I have the same problem as @imranalisolanki. I would also like to know how to use/implement the websocket from this example https://github.com/raymondfeng/loopback4-example-websocket/ in this example https://github.com/strongloop/loopback4-example-shopping .

  5. xdien commented on Jun 23, 2020

    @xdien

    I have been following this topic for a long time. Everyone who has done it successfully with https://github.com/strongloop/loopback4-example-shopping.
    Particularly https://github.com/raymondfeng/loopback4-example-websocket/ using httpserver with "Express" I do not know how to implement with RestExplorerComponent

  6. alexkander commented on Jul 16, 2020

    @alexkander
    Contributor

    Hi guys, I had the same problem: Looback 4 RestApplication + socket.io. I solved it based on loopback4-example-todo-list and loopback4-example-websocket. Here is the partial codes:

    • Instancing HttpServer with this.restServer.requestHandler: src/application.ts
    • Calling app.startWebSocket() in main function and add websocket options: src/index.ts

    I am starting with LB4, and I don't know what are the future repercussions of this implementation or if it is a bad practice, but, at the moment, it works for me and maybe for you too.

    -------------------------- Updated ---------------------

    To inject dependencies of the main app into websocket controllers you must inherit the websocket context of the main context

  7. xdien commented on Jul 19, 2020

    @xdien

    thanks @arondn2 . I will try to integrate it into my program

  8. imranalisolanki commented on Jul 20, 2020

    @imranalisolanki
    Author

    Hi @arondn2 . when i integrate in my program i am getting error.
    Error: The key 'authentication.actions.authenticate' is not bound to any value in context application

  9. alexkander commented on Jul 20, 2020

    @alexkander
    Contributor

    hi @imranalisolanki. I had a similar problem after my first comment in this feed. It is because websocket has not the same context of app. If you have a regular loopbak 4 app like loopback4-example-todo-list you must inherit the websocket context of the main context. I did with this changes.

    -------------------------- Updated ---------------------

    The links were wrong. I have updated them.

  10. d-bo commented on Jul 22, 2020

    @d-bo

    @arondn2 httpserver and websocketserver must have different ports ? I get Cannot start the application. { Error: listen EADDRINUSE: address already in use :::5000

    index.ts used from src/index.ts

  11. xdien commented on Jul 24, 2020

    @xdien

    @d-bo I successfully handled the web when I changed port 5000 to a different port than the http server. index.js

    if (require.main === module) {
      // Run the application
      const config = {
        rest: {
          port: +(process.env.PORT || 3000),
          host: process.env.HOST,
          protocol: process.env.HTTPS === "1" ? "https" : "http",
          key: fs.readFileSync(path.join(__dirname, './ssl/private/server-key.pem')).toString(),
          cert: fs.readFileSync(path.join(__dirname, './ssl/private/server-cert.pem')).toString(),
          // The `gracePeriodForClose` provides a graceful close for http/https
          // servers with keep-alive clients. The default value is `Infinity`
          // (don't force-close). If you want to immediately destroy all sockets
          // upon stop, set its value to `0`.
          // See https://www.npmjs.com/package/stoppable
          gracePeriodForClose: 5000, // 5 seconds
          openApiSpec: {
            // useful when used with OpenAPI-to-GraphQL to locate your application
            setServersFromRequest: true,
          },
        },
        websocket: { port: 5000 }
      };
      application.main(config).catch(err => {
        console.error('Cannot start the application.', err);
        process.exit(1);
      });
    }
    
  12. d-bo commented on Jul 24, 2020

    @d-bo

    @xdien just commented out original http server from skeleton app. finally both websocket and http server are on the same port:

    // src/index.ts
    
    // ...
    
    export async function main(options: ApplicationConfig = {}) {
      const app = new PrjApplication(options);
      await app.boot();
      // commented out original http server
      //await app.start();
      await app.startWebSocket();
    
      const url = app.restServer.url;
      console.log(`Server is running at ${app.httpServer.url}/api`);
    
      return app;
    }
    
    // ...
  13. alexkander commented on Jul 24, 2020

    @alexkander
    Contributor

    I didn't need to comment on that line. I made a complete example with the integration: loopback4-example-websocket-app. I hope it helps

  14. 37 remaining items

  15. w20k commented on Sep 24, 2020

    @w20k

    Thanks for a tip @arondn2.

    Minor note, who ever stumble on the same issue, after a day of debugging, for some reason (something related to: circular/connection issue) you cannot use 'server.io-client' from the NodeJS server (loopback4, in my case) to connect to internal/external server. It just doesn't let you (tried switching to transports: ['websocket'],upgrade: false - didn't help). By switching to 'ws' library issue was resolved!

  16. alexkander commented on Nov 6, 2020

    @alexkander
    Contributor

    Guys, There is a new loopback 4 module for socketio @loopback/socketio and example @loopback/example-socketio.

  17. justin65 commented on Jan 8, 2021

    @justin65

    @d-bo fine. I don't know why it works for me. I gonna try if that works in my proyect to make a refactoring of the example.

    @alexkander Did you find out the problem of "port in use" issue? I found that the key is the value of "host" in config.
    const config = { rest: { port, host: process.env.HOST ?? 'localhost', openApiSpec: { // useful when used with OpenAPI-to-GraphQL to locate your application setServersFromRequest: true, }, }, websocket: { port } };

    The value of "host" for "rest" is 'localhost' and for websocket is undefined. If you assign "locahost" to the host of websocket, you have able to repo the issue. I still have no idea for the solution.
    Thanks,
    Justin

  18. alexkander commented on Jan 8, 2021

    @alexkander
    Contributor

    @justin65 I couldn't even replicate the problem. If you could create a repo test with the minimum configuration that generates the error, I could review it.

  19. justin65 commented on Jan 8, 2021

    @justin65

    @alexkander I just fork the project and add a commit to replicate the problem.
    Could you please take a look for https://github.com/justin65/loopback4-example-websocket-app.git?
    I think the issue is caused by different http server instances in both rest and socketio. Am I right?

  20. alexkander commented on Jan 8, 2021

    @alexkander
    Contributor

    @justin65 with your repository I can replicate the problem. I'll take a look as soon as I can

  21. mAlaliSy commented on Jan 9, 2021

    @mAlaliSy

    Guys, There is a new loopback 4 module for socketio @loopback/socketio and example @loopback/example-socketio.

    How can I create a REST and socket.io application?

  22. justin65 commented on Jan 13, 2021

    @justin65

    @justin65 with your repository I can replicate the problem. I'll take a look as soon as I can

    @alexkander Did you have any update? Should both rest and socket.io share the same http server instance? Thanks.

  23. alexkander commented on Jan 13, 2021

    @alexkander
    Contributor

    @justin65 your fork is of a old repository. You should to use the example of socketio that currently loopback 4 has. @loopback/example-socketio. I gonna to archive my example repository because it is no longer stable.

    Anywhere, do you need set host configuration for websocket? I have commented it and it works!.

    websocket: {
        port,
        // host: 'localhost',
      }

    I gonna try to work in the documentation of the example and extension of socketio as soon as I can. Sorry for not being able to help more.

    Regards

  24. justin65 commented on Jan 14, 2021

    @justin65

    @alexkander I know that loopback 4 release a socketio example. But is't an Application, I can not extend it from rest application like the repository you are going to archive. That's why I keep working on old repository. Is there any guideline to merge two loopback 4 application?
    Regarding the host field, I just show you how to repo the 'port in use' problem. I can comment it, but I don't know what happened exactly.

    Regards

  25. ArtemShapovalov commented on Feb 2, 2021

    @ArtemShapovalov

    @aleksspeaker I'am trying to use host in websocket config but it leads to a problem Cannot start the application. Error: listen EADDRINUSE: address already in use 127.0.0.1:[port]

  26. d-bo commented on Feb 2, 2021

    @d-bo

    @justin65 , @ArtemShapovalov guys there is a working websocket repo built from original lb4 skeleton app https://github.com/d-bo/lb4-client-err where EADDRINUSE: address already in use problem solved.

    And the line causing this error https://github.com/d-bo/lb4-client-err/blob/173b996da0974f2a39f20ac0c53f67d95be0c29b/src/index.ts#L14

  27. ArtemShapovalov commented on Feb 2, 2021

    @ArtemShapovalov

    @d-bo thanks a lot it solve problem with EADDRINUSE but now I see undefined when server is started

    Server is running at undefined
    Try undefined/ping
    
  28. locked and limited conversation to collaborators on Mar 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions