moleculerjs / moleculer-io Goto Github PK
View Code? Open in Web Editor NEWSocket.io API GateWay service for Moleculer framework
License: MIT License
Socket.io API GateWay service for Moleculer framework
License: MIT License
I'm trying to register moleculer-io
in moleculer
using documentation with the following config:
import SocketIOService from 'moleculer-io'
const ioService = broker.createService({
name: 'io',
mixins: [SocketIOService],
settings: {
serveClient: false,
io: {
options: {
path: '/api/socket.io',
},
namespaces: {
'/': {
authorization: true,
},
},
},
},
});
Getting the error on the line mixins: [SocketIOService],
:
../src/services/socketio.ts:13:16 - error TS2322: Type 'Partial<IOServiceSchema>' is not assignable to type 'Partial<ServiceSchema<ServiceSettingSchema>>'.
Types of property 'methods' are incompatible.
Type '(Partial<IOMethods> & ThisType<IOServiceSchema>) | undefined' is not assignable to type 'ServiceMethods | undefined'.
Type 'Partial<IOMethods> & ThisType<IOServiceSchema>' is not assignable to type 'ServiceMethods | undefined'.
13 mixins: [SocketIOService],
~~~~~~~~~~~~~~~
I use the following versions of packages:
"moleculer": "0.14.29",
"moleculer-io": "2.2.0",
"moleculer-web": "0.10.5",
What should I pass to mixins to fix typing error?
this looks like a great library - I'm hesitant to try it out due to the fact many serverless, cloud hosting solutions today do not support socket.io.
What is your preferred hosting solution? Do you have some documentation for deploying moleculer-io? This might be something that could be covered on the readme after Cors...
It seems that moleculer-io is not compatible with new Moleculer release. I'm trying to join room, but when I get room list its always empty. What I'm doing wrong?
After upgrading to 1.0.0, I'm having this problem:
ReferenceError: debug is not defined
at
return _asyncToGenerator(function* () {
debug('brocast: ', ctx.params);
let namespace = _this2.io;
Shouldn't it be _this2.logger.debug('broadcast: ', ctx.params);
Hi,
There is some issue when you close the socket.io server in the stopped
lifecycle handler.
Try to start an example without npm, just with naked node:
node examples/full/index.js
If started, open the browser, client will connect and press once CTRL+C.
The ServiceBroker can't stop.
If you start debugging you will see that the lib/index.js:105 callback doesn't triggered and the Promise will never be fulfilled.
Could you fix it? I don't know what is the root of the problem.
Is it possible to update the socketio lib to latest version?
Hi @tiaod,
when will you make a new release? I'm trying to use it with moleculer-web but the last release doesn't contain this line: https://github.com/tiaod/moleculer-io/blob/master/src/index.js#L40
Thanks!
Hello,
I upgraded my socket.io-redis
package to @socket.io/redis-adapter
(package was renamed in 7.0
) As part of the instructions to migrate it expects an explicit creation of a Redis pub
and sub
instances. Furthermore, in the settings
object of my service schema, I used to have this:
//...
options: {
adapter: redisAdapter({
host: redisURL.hostname,
port: 6379,
}),
},
//...
And with the changes suggested by @socket.io/redis-adapter
,
import { createClient } from "redis";
import { createAdapter } from "@socket.io/redis-adapter";
const pubClient = createClient({ url: `redis://${redisURL.hostname}:6379` });
const subClient = pubClient.duplicate();
//...
options: {
adapter: createAdapter(pubClient, subClient),
},
throws an error with this stack trace:
ClientClosedError: The client is closed
at Commander._RedisClient_sendCommand (/Users/rishi/work/threetwo-core-service/node_modules/@redis/client/dist/lib/client/index.js:482:31)
at Commander.commandsExecutor (/Users/rishi/work/threetwo-core-service/node_modules/@redis/client/dist/lib/client/index.js:193:154)
at Commander.BaseClass.<computed> [as publish] (/Users/rishi/work/threetwo-core-service/node_modules/@redis/client/dist/lib/commander.js:8:29)
at RedisAdapter.broadcast (/Users/rishi/work/threetwo-core-service/node_modules/@socket.io/redis-adapter/dist/index.js:473:28)
at BroadcastOperator.emit (/Users/rishi/work/threetwo-core-service/node_modules/socket.io/dist/broadcast-operator.js:125:26)
at Namespace.emit (/Users/rishi/work/threetwo-core-service/node_modules/socket.io/dist/namespace.js:170:73)
at SocketService.handler (/Users/rishi/work/threetwo-core-service/node_modules/moleculer-io/src/index.js:214:16)
at /Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/utils.js:212:22
at processCheckResponse (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/validators/base.js:63:29)
at validateContextParams (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/validators/base.js:88:15)
at ServiceBroker.timeoutMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/timeout.js:31:14)
at ServiceBroker.fallbackMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/fallback.js:31:11)
at ServiceBroker.errorHandlerMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/error-handler.js:14:10)
at ServiceBroker.tracingLocalActionMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/tracing.js:101:12)
at ServiceBroker.call (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/service-broker.js:1215:31)
at Queue.<anonymous> (/Users/rishi/work/threetwo-core-service/services/importqueue.service.ts:248:25) {
[stack]: 'Error: The client is closed\n' +
' at Commander._RedisClient_sendCommand (/Users/rishi/work/threetwo-core-service/node_modules/@redis/client/dist/lib/client/index.js:482:31)\n' +
' at Commander.commandsExecutor (/Users/rishi/work/threetwo-core-service/node_modules/@redis/client/dist/lib/client/index.js:193:154)\n' +
' at Commander.BaseClass.<computed> [as publish] (/Users/rishi/work/threetwo-core-service/node_modules/@redis/client/dist/lib/commander.js:8:29)\n' +
' at RedisAdapter.broadcast (/Users/rishi/work/threetwo-core-service/node_modules/@socket.io/redis-adapter/dist/index.js:473:28)\n' +
' at BroadcastOperator.emit (/Users/rishi/work/threetwo-core-service/node_modules/socket.io/dist/broadcast-operator.js:125:26)\n' +
' at Namespace.emit (/Users/rishi/work/threetwo-core-service/node_modules/socket.io/dist/namespace.js:170:73)\n' +
' at SocketService.handler (/Users/rishi/work/threetwo-core-service/node_modules/moleculer-io/src/index.js:214:16)\n' +
' at /Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/utils.js:212:22\n' +
' at processCheckResponse (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/validators/base.js:63:29)\n' +
' at validateContextParams (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/validators/base.js:88:15)\n' +
' at ServiceBroker.timeoutMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/timeout.js:31:14)\n' +
' at ServiceBroker.fallbackMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/fallback.js:31:11)\n' +
' at ServiceBroker.errorHandlerMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/error-handler.js:14:10)\n' +
' at ServiceBroker.tracingLocalActionMiddleware (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/middlewares/tracing.js:101:12)\n' +
' at ServiceBroker.call (/Users/rishi/work/threetwo-core-service/node_modules/moleculer/src/service-broker.js:1215:31)\n' +
' at Queue.<anonymous> (/Users/rishi/work/threetwo-core-service/services/importqueue.service.ts:248:25)',
[message]: 'The client is closed'
}
What am I doing wrong?
I want to use the connection event like this is there any way to do this
io.on("connection",((socket) => {
console.log(socket)
})
events:{
'call':{
whitelist: [
'chatroom.*'
],
before: async function(ctx, socket, args){ //before hook
//args: An object includes { action, params, callOptions }
this.logger.info(this.getMeta(socket))
},
after: async function(ctx, socket, res){ //after hook
// res: The respose data.
this.logger.info(this.getMeta(socket))
}
},
'disconnecting': async function( reason){ // write your handler function here.
//var socket = this;
console.log("disconnecting", reason);
},
'disconnect': async function(reason){ // write your handler function here.
//var socket = this;
console.log("disconnect", reason);
},
}
The disconnect
event will not registered.
Maybe, there is problem in this loop:
for(let event in events){
let handlerItem = events[event]
if(typeof handlerItem === 'function'){ //custom handler
this.handlers[nsp][event] = handlerItem
return =======> should not return, continue loop
}
this.handlers[nsp][event] = this.makeIOHandler(handlerItem)
}
Wound be good to have an option to start the server with certificates like moleculer-web
If using params validation: https://moleculer.services/docs/0.13/validating.html
and call of action invalid, app broken with error:
Error action "io.call" with error: ValidationError: Parameters validation error!
Helps only restart
node.js 6 nearly of end of life.
Since node.js 8 you can relax on async/await
Hi @tiaod,
are you still maintaining this repo? If not, could you transfer the repo into the moleculerjs organization on Github, and transfer the NPM access to me?
Thanks, in advance!
With version 0.14 now its possible to overwrite strategy like round robin or shard.
For websockets, sometimes the context of a connections is in the service being called, if you have multiple services, you need to keep the user going to the same service using Shard Strategy, so context (example: recording an audio) will be available.
Will it work out of the box or does it need modification on the code?
Hi, went to this library by navigating through moleculer and i wanted to try this one.
I did face an issue which for sure is a misunderstanding from my part.
Here is the problem:
I created a basic service (io.service.js) with the following content:
const SocketIOService = require("moleculer-io");
module.exports = {
name: "io",
mixins: [SocketIOService],
settings: {
// Exposed port
port: process.env.PORT || 3000,
io: {
options: {},
namespaces: {
"/": {
events: {
call: {
whitelist: ["chat.*", "math.*"],
onBeforeCall: async function (ctx, socket, action, params) {
//before hook
console.log("before hook:", params);
},
onAfterCall: async function (ctx, socket, res) {
//after hook
console.log("after hook", res);
// res: The respose data.
}
}
}
}
}
}
}
}
In another service (chat.service.js) i did add this method:
actions: {
message: {
param: {},
/** @param {Context} ctx */
handler(ctx) {
this.broker.call("io.broadcast", {
event: "incomingMessage",
args: [ctx.params],
});
return ctx.params;
}
}
}
In another Vue CLI application i wanted to use the service defined above. Basically i just connect to the socket and send a message.
The connection is done by:
Vue.use(new VueSocketIO({
debug: false,
connection: 'http://localhost:3000',
}))
And i send the message successfully by doing this into a component:
sendMessage() {
this.$socket.emit(
"call",
"chat.message",
this.messageText,
(err, res) => {
if (err) {
console.error(err);
} else {
this.chatMessages.push(res);
this.messageText = "";
}
}
);
}
At this point everything is OK.
The issue is i was not able to listen to the broadcasted event (incomingMessage).
created() {
this.$socket.on("incomingMessage", data => {
console.log("Incoming message: ", data);
this.chatMessages.push(data);
});
}
Couldn't make this one work. If possible i would like a little explanation on how to listen to a broadcast event. This example was for a simple chat app.
If use localAction
middlewares, which throw some error, it make infinite recursion on io.call
actions
For fix it, need to place:
if (action.name === 'io.call') {
return next(ctx);
}
on each localAction
middleware
This code on 1.0.8 no more works:
broker.createService({
name: 'io',
mixins: [SocketIOService],
settings: {
port: 3000 //will call initSocketIO() on broker.start()
}
})
broker.start()
Need to add server: true
for proper listening on port:
broker.createService({
name: 'io',
mixins: [SocketIOService],
settings: {
port: 3000, //will call initSocketIO() on broker.start()
server: true
}
})
broker.start()
I got this message when try to leave a array of rooms
[2019-03-21T07:07:37.634Z] ERROR 32e7b0baa36c-15/API: Request error! TypeError : this.leaveRoom is not a function
TypeError: this.leaveRoom is not a function
at Promise.all.ctx.meta.$leave.map.room (/app/node_modules/moleculer-io/lib/index.js:172:64)
at Array.map (<anonymous>)
at Service.handler (/app/node_modules/moleculer-io/lib/index.js:172:47)
Hi @icebob, how are you?
I tried to use moleculer-io in an ESM
project and I couldn't, so I decided to generate a port that is working well. The tests passed, although it displays a warning.
In addition to making some adjustments to the code, I used tsup
to generate, in addition to exporting, an ESM
version, and also generate a CommonJS
version.
I added the build
script that will create the dist folder.
My fork is here: https://github.com/524c/moleculer-io
If you could take a look and tell me what you think, I'd appreciate it.
Hello guys.
Can we have access to the socket io object inside services?
If I need to, for example, check the clients inside a room (io.sockets.clients('room')), whats the correct way of doing this?
Thanks!
As part of Tracing would it be possible to connect all the message calls on a socket to a single context object?
I've been trying to do it myself but I'm really struggling with the context object, it doesn't really behave how I would expect it to.
I also use custom events which are only passed the message data and not a context object.
Essentially what I'm hopping for is a long running trace from which all subsequent calls are logged against and ended when the socket itself disconnects.
At the moment what I'm trying is to co-opting the authentication method and use it to create a new context object. Which I then attach to the socket for subsequent messages to use when making sub calls rather than directly via the broker attached to the Socket IO service.
Hello, I have to check token with my user service in order to validate it.
So, I need to access current context in socketAuthorize method.
Since it is a socket.io middleware and there is no context when it is defined I couldn't able to find a workaround.
Could you suggest something?
Hello, I am using the moleculer-template-project-typescript for my services. I do have a socket.io service based off of this example.
Here's the relevant code in the server:
"use strict";
import {
Context,
Service,
ServiceBroker,
ServiceSchema,
Errors,
} from "moleculer";
import SocketIOService from "moleculer-io";
export default class LibrarySocketService extends Service {
// @ts-ignore
public constructor(
public broker: ServiceBroker,
schema: ServiceSchema<{}> = { name: "librarysocket" }
) {
super(broker);
this.parseServiceSchema(
Service.mergeSchemas(
{
name: "librarysocket",
mixins: [SocketIOService],
settings: {
port: 3001,
io: {
options: {
// adapter: redisAdapter({ host: 'localhost', port: 6379 })
},
namespaces: {
"/": {
middlewares: [
function (socket, next) {
console.log("namespace middleware"); //point to service instance.
next();
}
],
// packetMiddlewares:[],
events: {
call: {
whitelist: ["import.*", "imagetransformation.*", "comicvine.*", "librarysocket.*"],
onBeforeCall: async function (
ctx,
socket,
action,
params,
callOptions
) {
console.log("before hook:", { action, params, callOptions });
},
onAfterCall: async function (ctx, socket, res) {
console.log("after hook", res);
}
// callOptions:{}
},
hello: async function ({ name, type }, file, respond) {
console.log("hello", name)
}
}
}
}
}
},
hooks: {},
actions: {
},
methods: {},
},
schema
)
);
}
}
The API Gateway starts properly, but it seems that new connections are been spawned:
[2021-10-25T01:31:08.367Z] INFO mac-mini.localdomain-63071/LIBRARYSOCKET: (nsp:'/') Client connected: ud--MOhsrOxHYjtKABTp
namespace middleware
[2021-10-25T01:31:13.374Z] INFO mac-mini.localdomain-63071/LIBRARYSOCKET: (nsp:'/') Client connected: BVrLP7wGn6ra3ku2ABTq
namespace middleware
[2021-10-25T01:31:18.380Z] INFO mac-mini.localdomain-63071/LIBRARYSOCKET: (nsp:'/') Client connected: 8A5oSA0xkubgVf9yABTr
For what its worth, my React client has this code:
import React, { createContext, ReactElement } from "react";
import io, { Socket } from "socket.io-client";
import { SOCKET_BASE_URI } from "../../constants/endpoints";
import { useDispatch } from "react-redux";
import { RMQ_SOCKET_CONNECTED } from "../../constants/action-types";
import { success } from "react-notification-system-redux";
const WebSocketContext = createContext(null);
export const WebSocketProvider = ({ children }): ReactElement => {
const dispatch = useDispatch();
const socket: Socket = io(SOCKET_BASE_URI);
socket.on("connect", () => {
console.log("connected"); // <-- this never fires
dispatch({
type: RMQ_SOCKET_CONNECTED,
isSocketConnected: true,
socketId: socket.id,
});
});
socket.on("disconnect", () => {
console.log(`disconnect`);
});
const ws: any = {
socket,
};
return (
<WebSocketContext.Provider value={ws}>{children}</WebSocketContext.Provider>
);
};
export { WebSocketContext };
export default WebSocketProvider;
The socket never connects from the client, and socket.on("connect"...
never seems to succeed.
What am I doing wrong?
We should add some moleculer metrics. E.g.:
moleculer.io.sockets.total
(labels: namespace, room)actually I want to generete namespaces dynamicly on start up and add new namespace on runtime when new tenat is added to db.
example: multitenant helpdesk app
tenant is namespace
ticket is room
mail is message
usecase: new tenant registered
example2: map based game
map is namespace
one to one fight is room
damage is message
usecase: new map added to the game
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.