如何将socket.io导出到nodejs中的其他模块?

时间:2016-07-21 18:38:34

标签: javascript node.js socket.io

socket.io工作app.js但是当我尝试从其他模块调用它时,它不会创建io.connection不确定吗?

app.js

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var ditconsumer = require('./app/consumers/ditconsumer');
ditconsumer.start(io);
server.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});

consumer.js

module.exports = {
    start: function (io) {
        consumer.on('message', function (message) {
            logger.log('info', message.value);
            io.on('connection', function (socket) {
                socket.on('message', function(message) {
                    socket.emit('ditConsumer',message.value);
                    console.log('from console',message.value);
                });
            });
        });
}
}

8 个答案:

答案 0 :(得分:31)

由于app.js通常是应用程序中的主要初始化模块,它通常会初始化Web服务器和socket.io,并将加载应用程序所需的其他内容。

这种与其他模块共享io的典型方法是将它们传递给该模块的构造函数中的其他模块。这将是这样的:

var server = require('http').createServer(app);
var io = require('socket.io')(server);

// load consumer.js and pass it the socket.io object
require('./consumer.js)(io);

// other app.js code follows

然后,在consumer.js中:

// define constructor function that gets `io` send to it
module.exports = function(io) {
    io.on('connection', function(socket) {
        socket.on('message', function(message) {
            logger.log('info',message.value);
            socket.emit('ditConsumer',message.value);
            console.log('from console',message.value);
        });
    });
};

或者,如果您想使用.start()方法初始化事物,您可以对此做同样的事情(细微差别):

// app.js
var server = require('http').createServer(app);
var io = require('socket.io')(server);

// load consumer.js and pass it the socket.io object
var consumer = require('./consumer.js);
consumer.start(io);

// other app.js code follows

来自consumer.js的启动方法

// consumer.js
// define start method that gets `io` send to it
module.exports = {
    start: function(io) {
        io.on('connection', function(socket) {
            socket.on('message', function(message) {
                logger.log('info',message.value);
                socket.emit('ditConsumer',message.value);
                console.log('from console',message.value);
            });
        });
    };
}

这就是所谓的" push"资源共享模块。正在加载的模块通过在构造函数中传递它来向您推送一些共享信息。

还有"拉"模块本身在其他模块中调用方法来检索共享信息(在本例中为io对象)的模型。

通常情况下,任何一个模型都可以工作,但是考虑到如何加载模块以及谁拥有所需信息以及您希望模块在其他情况下如何重用,通常一个或另一个模型会更自然。

答案 1 :(得分:20)

如果您想避开全局范围,请将io存在于单独的文件中:

var sio = require('socket.io');
var io = null;

exports.io = function () {
  return io;
};

exports.initialize = function(server) {
  return io = sio(server);
};

然后在app.js

var server = require('http').createServer(app);
var io = require('./io').initialize(server);
require('./app/consumers/ditconsumer'); // loading module will cause desired side-effect
server.listen(...);

consumer.js

require('../io').io().on('connection', function(socket) {
  logger.log('info', message.value);
  socket.on('message', function(message) {
    socket.emit('ditConsumer',message.value);
    console.log('from console',message.value);
  });
});

答案 2 :(得分:2)

你可以只用4行制作一个单例实例。

在websocket.js中编写服务器配置代码。

const socketIO = require('socket.io');
const server = require('http').createServer();
server.listen(8000);

module.exports = socketIO(server);

然后在您的consumer.js中只需要文件

const socket = require('./websocket');

/* API logic here */

socket.emit('userRegistered', `${user.name} has registered.`);

答案 3 :(得分:2)

对我来说最有效的方法是使用一个回调函数,该函数可以导出socket.io实例。 app.js:

var server = require('http').createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(socket) {
    socket.on('message', function(message) {
        logger.log('info',message.value);
        socket.emit('ditConsumer',message.value);
        console.log('from console',message.value);
    });
});
function getSocketIo(){
    return io;
}
module.exports.getSocketIo=getSocketIo

以及在Consumer.js中

const app=require('./app.js')
const io=app.getSocketIo()

答案 4 :(得分:1)

我发现简单的 solution 解决方案非常简单。在app.js中使用全局变量,然后从其他文件访问它。

global.io = require('socket.io').listen(server);

答案 5 :(得分:1)

您可以为 socket-io 创建一个单例类。

它看起来非常干净和模块化。

这是我的文件夹结构。

node.js folder structure

Socket.io.ts

在这个文件中,我初始化了 socket-io,并创建了 publishEvent() 方法以便我可以发布事件。

import {
  Server,
  Socket
} from "socket.io";
import {
  Events
} from "./utils";

export class SocketInit {
  private static _instance: SocketInit;

  socketIo: Server;

  constructor(io: Server) {
    this.socketIo = io;
    this.socketIo.on("connection", (socket: Socket) => {
      console.log("User connected");
    });
    SocketInit._instance = this;
  }

  public static getInstance(): SocketInit {
    return SocketInit._instance;
  }

  public publishEvent(event: Events, data: any) {
    this.socketIo.emit(event, data);
  }
}

Server.ts

import "reflect-metadata";
import {
  config
} from "dotenv";
config();
import http from "http";
import express, {
  Request,
  Response
} from "express";
import {
  Server,
  Socket
} from "socket.io";
import mongoose from "mongoose";
import cors from "cors";
import path from "path";
import morgan from "morgan";
import {
  SocketInit
} from "./socket.io";
import {
  downloadsRouter
} from "./routes/downloads";

const app = express();

const server = http.createServer(app);

export const io = new Server(server, {
  cors: {
    origin: "*"
  },
});

//Initilize socket
new SocketInit(io);

mongoose
  .connect("mongodb://localhost:27017/youtube", {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  })
  .then(() => {
    console.log("Connected to database");
  })
  .catch((error) => {
    throw error;
  });

app.use(morgan("dev"));
app.use(express.json());
app.use(express.urlencoded({
  extended: true
}));
app.set("view engine", "ejs");
app.use(express.static(path.join(__dirname, "views")));
app.use(cors());
app.use(downloadsRouter);

app.get("/", (req: Request, res: Response) => {
  res.render("index");
});

server.listen(3000, () => {
  console.log("Server running up 3000");
});

download-queue.ts 在这个文件中,我执行一些下载任务并为客户端发出事件。

import Bull from "bull";
import ytdl from "ytdl-core";
import fs from "fs";
import {
  Video
} from "../models/video";
import {
  Events
} from "../utils";
import {
  SocketInit
} from "../socket.io";

const downloadQueue = new Bull("download queue", {
redis: {
  host: process.env.REDIS_HOST!,
  port: parseInt(process.env.REDIS_PORT!),
},
});
);

downloadQueue.process((job, done) => {
  return new Promise((resolve, reject) => {
    const title = Math.random().toString();
    const {
      youtubeUrl
    } = job.data;

    //Get singleton instance
    const socket = SocketInit.getInstance();

    ytdl(youtubeUrl)
      .pipe(fs.createWriteStream(`${process.cwd()}/downloads/${title}.mp4`))
      .on("finish", async() => {
        socket.publishEvent(Events.VIDEO_DOWNLOADED, title);

        console.log("Download complete");

        const file = `${process.cwd()}/downloads/${title}.mp4`;

        const video = new Video({
          title,
          file,
        });

        await video.save();

        done();

        resolve({
          title
        });
      })
      .on("ready", () => {
        console.log("Download started");
        socket.publishEvent(Events.VIDEO_STARTED, title);
      })
      .on("error", (error) => {
        socket.publishEvent(Events.VIDEO_ERROR, error);
        done(error);
        reject(error);
      });
  });
});

export {
  downloadQueue
};

答案 6 :(得分:0)

我创建了一个带有SocketService类的文件socket.service.ts,并在app.ts中用http调用了构造函数。这也适用于纯JavaScript,只需更改进出口即可。

import * as socketIo from 'socket.io';

export class SocketService {

  io: any;

  constructor(http) {
    this.io = socketIo(http)
    this.io.set('origins', '*:*');
    this.io.on('connection', function (socket) {
      console.log('an user connected');
      socket.on('disconnect', function () {
        console.log('user disconnected');
      });
    });

    http.listen(3001, function () {
      console.log('socket listening on *:3001');
    });

  }

}
app.ts通话中

就像:

import * as express from 'express';

import { SocketService } from './services/socket.service';

const app = express(); 
var http = require('http').Server(app);

// ...

new SocketService(http);

// ...

module.exports = app;

请注意,每次调用构造函数时,都会创建一个新实例。为了避免这种情况,请使用单例模式:)

答案 7 :(得分:0)

您可以非常容易地做到这一点,您只需要在app.js中编写套接字连接即可,然后您可以在任何需要的地方使用套接字

在app.js文件中输入如下代码

 var http = require('http').createServer(app);
 const io = require('socket.io')(http);  

 io.sockets.on("connection", function (socket) {
 // Everytime a client logs in, display a connected message
 console.log("Server-Client Connected!");

 socket.join("_room" + socket.handshake.query.room_id);

 socket.on('connected', function (data) {

  });
});

const socketIoObject = io;
module.exports.ioObject = socketIoObject;
http.listen(port, () => {
    console.log('Magic happens on port ' + port); // shoutout to the user
});

在任何文件或controller中,您都可以像下面那样导入该对象

 const socket = require('../app'); //import socket  from app.js

    //you can emit or on the events as shown 
 socket.ioObject.sockets.in("_room" + req.body.id).emit("msg", "How are You ?");

这很容易解决了我的问题