Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

How to integrate socket in loopback 4 server API #4044

Closed
imranalisolanki opened this issue Nov 4, 2019 · 63 comments
Closed

How to integrate socket in loopback 4 server API #4044

imranalisolanki opened this issue Nov 4, 2019 · 63 comments
Assignees

Comments

@imranalisolanki
Copy link

imranalisolanki commented Nov 4, 2019

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.

@hacksparrow
Copy link
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.

@imranalisolanki
Copy link
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;
}

@hacksparrow
Copy link
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.

@kchraniuk
Copy link

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 .

@xdien
Copy link

xdien commented Jun 23, 2020

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

@alexkander
Copy link
Contributor

alexkander commented Jul 16, 2020

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

@xdien
Copy link

xdien commented Jul 19, 2020

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

@imranalisolanki
Copy link
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

@alexkander
Copy link
Contributor

alexkander commented Jul 20, 2020

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.

@d-bo
Copy link

d-bo commented Jul 22, 2020

@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

@xdien
Copy link

xdien commented Jul 24, 2020

@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);
  });
}

@d-bo
Copy link

d-bo commented Jul 24, 2020

@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;
}

// ...

@alexkander
Copy link
Contributor

alexkander commented Jul 24, 2020

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

@d-bo
Copy link

d-bo commented Jul 28, 2020

I try to inject websocket controller into notification.controller via

constructor(
    @inject('controllers.WebSocketController') private ws: WebSocketController,
) {}

Seems it is not the right way doing that:

500 ResolutionError: The key 'ws.socket' is not bound to any value in context 
RequestContext-6bGhwRlvTmCH8MjrUYqIBQ-4 (context: RequestContext-6bGhwRlvTmCH8MjrUYqIBQ-4, 
binding: ws.socket, resolutionPath: controllers.NotificationController --> 
@NotificationController.constructor[4] --> controllers.WebSocketController --> 
@WebSocketController.constructor[0])

@alexkander
Copy link
Contributor

@d-bo why are you trying to inject a controller into another controller? I assume notification.controller is a regular rest controller to handle HTTP requests, and WebSocketController is to handle connections socket.io. WebSocketController need the socket instance from socket.io connection which doesn't exist in a HTTP request.

@d-bo
Copy link

d-bo commented Jul 28, 2020

@arondn2 i need to emit incoming data from rest notification.controller to websocket

// for example
@post('/notifications')
async create(data: any) {
    ...
    this.socket.emit('notification', data);
}

tried inject only socket

constructor(
    @ws.socket() private socket: Socket,
) {}

no luck) same 500 ResolutionError ...

@alexkander
Copy link
Contributor

@d-bo I think you have to implement a room scheme like socket.io explains in their documentation here. I added some code in loopback4-example-websocket-app repo to show you a way to implement it, specifically how to emit an event from TodoController (Http request controller) to socket.io room. The specifics changes are:

  • Require refractor of WebSocketServer and Websocket.docorator
  • Named websocket controller: link
  • Join socket to specific room: link
  • Implementation of Http endpoint to emit event: link. Here you can seed how to inject namespace instance with the name of the websocket controller.
  • Example how to use in client:

@argupta23
Copy link

argupta23 commented Jul 29, 2020

@arondn2,

Thanks for sharing the updated repo.

I just downloaded your updated version and it looks like we still have an issue with "port in use".

`> [email protected] prestart /home/zzz/latesttry/loopback/lb4/loopback4-example-websocket-app

npm run build

[email protected] build /home/zzz/latesttry/loopback/lb4/loopback4-example-websocket-app
lb-tsc

[email protected] start /home/zzz/latesttry/loopback/lb4/loopback4-example-websocket-app
node .

Cannot start the application. Error: listen EADDRINUSE: address already in use 127.0.0.1:3000
at Server.setupListenHandle [as _listen2] (net.js:1313:16)
at listenInCluster (net.js:1361:12)
at GetAddrInfoReqWrap.doListen [as callback] (net.js:1498:7)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:68:8) {
code: 'EADDRINUSE',
errno: 'EADDRINUSE',
syscall: 'listen',
address: '127.0.0.1',
port: 3000
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: node .
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
`

netstat -tulpn (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN - tcp 0 0 172.20.20.235:5432 0.0.0.0:* LISTEN - tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN - tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN - tcp 0 0 127.0.0.1:6012 0.0.0.0:* LISTEN - tcp 0 0 172.20.20.235:6379 0.0.0.0:* LISTEN - tcp6 0 0 :::22 :::* LISTEN - tcp6 0 0 ::1:6010 :::* LISTEN - tcp6 0 0 ::1:6011 :::* LISTEN - tcp6 0 0 ::1:6012 :::* LISTEN - tcp6 0 0 :::80 :::* LISTEN - udp 0 0 127.0.0.53:53 0.0.0.0:* - udp 0 0 172.20.20.235:68 0.0.0.0:* -

Will appreciate if you can please look into it.

Thanks

@alexkander
Copy link
Contributor

alexkander commented Jul 29, 2020

@argupta23 Sorry, i can't get this issue but I am looking at what is happening.
Have you tried removing the node_modules folder, reinstalling dependencies?
Can you use npm run clean && npm run start instead of npm run build, lb-tsc and node .?

@argupta23
Copy link

@d-bo

I am in the same situation as you and trying to achieve something similar.

@arondn2

Yes, I did what you suggested but have the same result.

I even tried the suggestion that was earlier made to comment out app.start(), but that made matters worse.

To get around the issue, within index.ts, I appended the port with 5000 and it seems to comeup.
websocket: { port: 5000 }
It also requires public/index.html to listen on 5000

But in this case we now have the app running on 2 ports (3000 and 5000).

Hope this helps. Please let me know if you want me try something else.

@alexkander
Copy link
Contributor

alexkander commented Jul 29, 2020

@argupta23 I will comment this when I find out the issue.
@d-bo, do you have the same problem with the port? were you start the repo example that I left?

@alexkander
Copy link
Contributor

@argupta23 I have run the example in 3 differents computers and it always run ok. I have noticed you haven't run netstat command as root, and logs are says Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all, which means those are not all the proccesses. Please trying using another port in src/index.js

@d-bo
Copy link

d-bo commented Jul 29, 2020

@arondn2 no, i didn't clone the repo loopback4-example-websocket-app. I took files and pieces of code and port them to skeleton app generated from lb4 cli ...

@argupta23
Copy link

@d-bo, does your version comeup on a single port?

@arondn2,

Just ran a quick test again for you and here is the output.

ubuntu: 20.04 running kernel 5.4.0-40-generic
node -v : 12.18.2
npm -v : 6.14.7

and package.json

{
"name": "@loopback/example-file-transfer",
"version": "1.4.2",
"description": "Example application for file upload/download with LoopBack 4",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"engines": {
"node": ">=10.16"
},
"author": "IBM Corp.",
"copyright.owner": "IBM Corp.",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"scripts": {
"acceptance": "lb-mocha "dist/tests/acceptance//*.js"",
"build": "lb-tsc",
"build:watch": "lb-tsc --watch",
"clean": "lb-clean example-file-transfer.tgz dist *.tsbuildinfo package",
"verify": "npm pack && tar xf example-file-transfer.tgz && tree package && npm run clean",
"lint": "npm run prettier:check && npm run eslint",
"lint:fix": "npm run eslint:fix && npm run prettier:fix",
"prettier:cli": "lb-prettier "
/.ts" "**/.js"",
"prettier:check": "npm run prettier:cli -- -l",
"prettier:fix": "npm run prettier:cli -- --write",
"eslint": "lb-eslint --report-unused-disable-directives .",
"eslint:fix": "npm run eslint -- --fix",
"pretest": "npm run clean && npm run build",
"test": "lb-mocha "dist/tests//*.js"",
"test:dev": "lb-mocha dist/tests/
/*.js && npm run posttest",
"prestart": "npm run build",
"start": "node ."
},
"repository": {
"type": "git",
"url": "https://github.com/strongloop/loopback-next.git",
"directory": "examples/file-transfer"
},
"dependencies": {
"@loopback/boot": "^2.4.0",
"@loopback/core": "^2.9.2",
"@loopback/repository": "^2.10.0",
"@loopback/rest": "^5.2.1",
"@loopback/rest-explorer": "^2.2.7",
"loopback-connector-mongodb": "^5.3.0",
"multer": "^1.4.2",
"tslib": "^2.0.0"
},
"devDependencies": {
"@loopback/build": "^6.1.1",
"@loopback/eslint-config": "^8.0.4",
"@loopback/testlab": "^3.2.1",
"@types/express-serve-static-core": "^4.17.8",
"@types/multer": "^1.4.3",
"@types/node": "^10.17.27",
"eslint": "^7.5.0",
"typescript": "~3.9.7"
},
"keywords": [
"loopback",
"LoopBack",
"example",
"file",
"upload"
],
"gitHead": "5538896411bb56467ae52670a29d1aec1690be74"
}

sudo netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 816/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 902/sshd: /usr/sbin
tcp 0 0 172.20.20.235:5432 0.0.0.0:* LISTEN 56555/postgres
tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN 704372/sshd: argupt
tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN 712372/sshd: argupt
tcp 0 0 172.20.20.235:6379 0.0.0.0:* LISTEN 43528/redis-server
tcp6 0 0 :::22 :::* LISTEN 902/sshd: /usr/sbin
tcp6 0 0 ::1:6010 :::* LISTEN 704372/sshd: argupt
tcp6 0 0 ::1:6011 :::* LISTEN 712372/sshd: argupt
tcp6 0 0 :::80 :::* LISTEN 54445/apache2
udp 0 0 127.0.0.53:53 0.0.0.0:* 816/systemd-resolve
udp 0 0 172.20.20.235:68 0.0.0.0:* 814/systemd-network

set websocket port to blank
loopback4-example-websocket-app$ vi src/index.ts
loopback4-example-websocket-app$ npm start

[email protected] prestart /home/argupta/latesttry/loopback/lb4/loopback4-example-webs
npm run build
[email protected] build /home/argupta/latesttry/loopback/lb4/loopback4-example-websock
lb-tsc
[email protected] start /home/argupta/latesttry/loopback/lb4/loopback4-example-websock
node .

Cannot start the application. Error: listen EADDRINUSE: address already in use 127.0.0.1:3000
at Server.setupListenHandle [as _listen2] (net.js:1313:16)
at listenInCluster (net.js:1361:12)
at GetAddrInfoReqWrap.doListen [as callback] (net.js:1498:7)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:68:8) {
code: 'EADDRINUSE',
errno: 'EADDRINUSE',
syscall: 'listen',
address: '127.0.0.1',
port: 3000
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: node .
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /home/argupta/.npm/_logs/2020-07-29T20_14_16_107Z-debug.log

sudo netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 816/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 902/sshd: /usr/sbin
tcp 0 0 172.20.20.235:5432 0.0.0.0:* LISTEN 56555/postgres
tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN 704372/sshd: argupt
tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN 712372/sshd: argupt
tcp 0 0 172.20.20.235:6379 0.0.0.0:* LISTEN 43528/redis-server
tcp6 0 0 :::22 :::* LISTEN 902/sshd: /usr/sbin
tcp6 0 0 ::1:6010 :::* LISTEN 704372/sshd: argupt
tcp6 0 0 ::1:6011 :::* LISTEN 712372/sshd: argupt
tcp6 0 0 :::80 :::* LISTEN 54445/apache2
udp 0 0 127.0.0.53:53 0.0.0.0:* 816/systemd-resolve
udp 0 0 172.20.20.235:68 0.0.0.0:* 814/systemd-network

updated websocket port to 5000

loopback4-example-websocket-app$ vi src/index.ts
loopback4-example-websocket-app$ sudo netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 816/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 902/sshd: /usr/sbin
tcp 0 0 172.20.20.235:5432 0.0.0.0:* LISTEN 56555/postgres
tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN 704372/sshd: argupt
tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN 712372/sshd: argupt
tcp 0 0 172.20.20.235:6379 0.0.0.0:* LISTEN 43528/redis-server
tcp6 0 0 :::22 :::* LISTEN 902/sshd: /usr/sbin
tcp6 0 0 ::1:6010 :::* LISTEN 704372/sshd: argupt
tcp6 0 0 ::1:6011 :::* LISTEN 712372/sshd: argupt
tcp6 0 0 :::80 :::* LISTEN 54445/apache2
udp 0 0 127.0.0.53:53 0.0.0.0:* 816/systemd-resolve
udp 0 0 172.20.20.235:68 0.0.0.0:* 814/systemd-network

loopback4-example-websocket-app$ npm start

[email protected] prestart /home/argupta/latesttry/loopback/lb4/loopback4-example-webs
npm run build
[email protected] build /home/argupta/latesttry/loopback/lb4/loopback4-example-websock
lb-tsc
[email protected] start /home/argupta/latesttry/loopback/lb4/loopback4-example-websock
node .

Server is running at http://127.0.0.1:3000

ran netstat -tulpn from another terminal
sudo netstat -tulpn
[sudo] password for argupta:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 816/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 902/sshd: /usr/sbin
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN 715259/node
tcp 0 0 172.20.20.235:5432 0.0.0.0:* LISTEN 56555/postgres
tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN 704372/sshd: argupt
tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN 712372/sshd: argupt
tcp 0 0 172.20.20.235:6379 0.0.0.0:* LISTEN 43528/redis-server
tcp6 0 0 :::22 :::* LISTEN 902/sshd: /usr/sbin
tcp6 0 0 ::1:6010 :::* LISTEN 704372/sshd: argupt
tcp6 0 0 ::1:6011 :::* LISTEN 712372/sshd: argupt
tcp6 0 0 :::5000 ::: LISTEN 715259/node*
tcp6 0 0 :::80 :::* LISTEN 54445/apache2
udp 0 0 127.0.0.53:53 0.0.0.0:* 816/systemd-resolve
udp 0 0 172.20.20.235:68 0.0.0.0:* 814/systemd-network

one thing to note is that the websocket is attached to an IPv6 address / port

@alexkander
Copy link
Contributor

alexkander commented Jul 29, 2020

I can see you are using different ports for the configurations of rest and websocket. In my previous comment I say change the port for both, not just for websocket.

// src/index.ts
if (require.main === module) {
  const port = process.env.PORT ?? 5000; ///<------- UPDATE HERE
  // Run the application
  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
    }
  };
  main(config).catch(err => {
    console.error('Cannot start the application.', err);
    process.exit(1);
  });
}

Also, it is very important to run npm run clean before npm start.

Anyway I don't know how I can help you more. I still thinking there is process using that port.

@d-bo
Copy link

d-bo commented Aug 4, 2020

@arondn2 the point is to push notifications to user logged in from many devices, browsers. to put user into own socket.io room after successfull authentication . so i tried all the matched variants from socket.io cheatsheet this.socket.in(`/pz#${userId}`).emit('authenticated'), this.socket.to(`/pz#${userId}`).emit('authenticated') ... client is not responding at all

@alexkander
Copy link
Contributor

@d-bo do you want to send the event to all others connections of the same authenticated user or of all users connected?

@d-bo
Copy link

d-bo commented Aug 4, 2020

@arondn2 to all other connections of the same authenticated user

@alexkander
Copy link
Contributor

@d-bo I think if you are using this.socket.in(`/pz#${userId}`).emit('authenticated') or this.socket.in(`/pz#${userId}`).emit('authenticated'), a simple client connection should received the event. Make sure you have socket.on('authenticated', function(){...}) in the client.

If you want send the event to all other connections of the same authenticated user, you will need to use broadcast, and to test it you will need several connections for the same user at the same time.

You need to create a minimal repository loopback project with this problem, because there's not much I can say to find out the problem if I can't have the entire view.

@sergiogaitan
Copy link

sergiogaitan commented Aug 5, 2020

Hi @arandn2 , I did what you said,but it keeps throwing me this error:
Cannot start the application. TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined at validateString (internal/validators.js:117:11) at Object.resolve (path.js:980:7) at new Bootstrapper (/Users/Sergio/Documents/kloustr/socketio/myIntSocketIO/my-int-socket-io/node_modules/@loopback/boot/src/bootstrapper.ts:46:24)
Do you know what might I be doing wrong?

@alexkander
Copy link
Contributor

@sergiogaitan I have say many things in this thread.. jajajajajajajaja... Please, tell me which of my comments you are talking about to try to help you.

Otherwise, did you run the example that I left?

@ahmed-adly-khalil
Copy link

@arondn2 Thanks for solving this issue, this example works great: https://github.com/arondn2/loopback4-example-websocket-app

@d-bo
Copy link

d-bo commented Aug 10, 2020

@arondn2 how to get io instance from rest / websocket controllers ? The broadcast don't comes from a socket.

@alexkander
Copy link
Contributor

async controllerMethod(
    @ws.server() io: Server
  ): Promise<any> {
      // ...
  }

regards, @d-bo

@w20k
Copy link

w20k commented Sep 22, 2020

Have anyone tried to implement the 'socket.io-client', loopback way?
@arondn2, thanks your example is awesome! ;)

@alexkander
Copy link
Contributor

alexkander commented Sep 22, 2020

hi @w20k. Here is a example how to use socket.io-client for a acceptance test. https://github.com/strongloop/loopback-next/blob/socketio/extensions/socketio/src/tests/acceptance/socketio.server.acceptance.ts. I think you need to install socket.io-client and @types/socket.io-client dependencies

@w20k
Copy link

w20k commented Sep 22, 2020

Hi, @arondn2 thanks for a quick answer. Probably my issue is a bit more complicated :)

I have a bidirectional connection via WebSocket where loopback is a middleman with (currently) Socket.io server (from the example). And now I need to figure out a proper way to initiate a connection to a server using the (as I've understood SocketIoServer doesn't support it?) 'socket.io-client', and somehow make those two websockets communicate, per user session_id. Communication part is not an issue, but to subscribe for client messages and push those on server.

Or that's the only option, and I'm overthinking 😄

@alexkander
Copy link
Contributor

alexkander commented Sep 22, 2020

@w20k I'm not sure I understand. The scheme that you are trying to explain is something like this:

  1. client (maybe a html/js page)
  2. Server middleman (Loopback4+socket.io)
  3. Main Server (Maybe Loopback4+socket.io)

And are you trying send messages from (1) to (2) and those message from (2) to (3)? For this you need server.io-client in (2)?

@w20k
Copy link

w20k commented Sep 22, 2020

@arondn2 yeah, you got it right.

  1. Client (html/js SPA + socket.io-client)
  2. Server middleman (Loopback4 + socket.io)
  3. Server Main (Java + Websocket)

It's a WebSocket connection between (1) - (3), where (2) is a "Websocket manager", of some sort.
And we need to send a message from (1) - (3) on login to establish a Websocket connection and back to client (3) - (1) if there were any updates.

And, yes, for this I was thinking I'd need to use 'server.io-client' in (2).

@alexkander
Copy link
Contributor

@w20k if (3) is public or visible for (1) you can connect directly to (3). But I think (3) is private or maybe you just is required connect through (2). If this is the case, my opinion is you must implement a kind of proxy, where client in (1) connects to server in (2) and a client in (2) using socket.io-client in loopback connects to server in (3).

Also (2) must catch events from client in (1) and emit them to server in (3) and catch events from server in (3) and emit them to (1).

You could do the latter linking event by event, or you could use socket.use (documentation) for dynamically linking.

@w20k
Copy link

w20k commented Sep 24, 2020

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!

@alexkander
Copy link
Contributor

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

@justin65
Copy link

justin65 commented Jan 8, 2021

@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

@alexkander
Copy link
Contributor

alexkander commented Jan 8, 2021

@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.

@justin65
Copy link

justin65 commented Jan 8, 2021

@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?

@alexkander
Copy link
Contributor

alexkander commented Jan 8, 2021

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

@mAlaliSy
Copy link

mAlaliSy commented Jan 9, 2021

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?

@justin65
Copy link

@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.

@alexkander
Copy link
Contributor

alexkander commented Jan 13, 2021

@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

@justin65
Copy link

@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

@ArtemShapovalov
Copy link

@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]

@d-bo
Copy link

d-bo commented Feb 2, 2021

@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

@ArtemShapovalov
Copy link

@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

@bajtos bajtos closed this as completed Mar 11, 2021
@loopbackio loopbackio locked and limited conversation to collaborators Mar 11, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests