ssocket
v2.1.14
Published
仿 Koa 中间件控制的 WebSocket 服务
Downloads
40
Maintainers
Readme
仿 Koa 中间件控制的 WebSocket 服务,食用简单,上手容易, 支持 GZIP 解压缩和 ProtoBuffer 解压缩配置,觉得小弟写的还行的话,就给个Star⭐️吧~
使用说明
点击安装客户端程序
运行方式
脚本示例
mkdir socket_test
cd socket_test
npm init --yes
npm i -s ssocket
vim app.js
# 输入此内容
// TS 引入方式 import Ssocket from "ssocket"
const Ssocket = require("ssocket").default;
const server = new Ssocket({
port: 8080
});
server.on("start-up", function(){
console.log("启动成功")
})
# 然后执行
# Node 安装自动百度
node app.js
// 控制台打印 启动成功
其他配置
const http = require("http")
const Ssocket = require("ssocket").default;
const httpServer = http.createServer()
const server = new Ssocket({
server: httpServer,
verifyClient: ({ origin, secure, req }, callback) => {
callback(true/**返回 false 的话,连接就会中断并给前端返回 403 的HTTP错误码 */)
}, // 非必传
perMessageDeflate: true, // 非必传
maxPayload: 1024 * 1024 * 10, // 最大传输单位 10M // 非必传
adapter:{// 非必传, 用于服务集群做消息同步
// MQ 交换机名称前缀
key:"SocketTipKey",
redis:{
prefix: 'im',
host: '127.0.0.1',
port: '6379',
expire: 60,
},
mqurl:"amqp://username:password@IP"
}
})
httpServer.listen(8080, function(){
console.log("启动成功")
})
ProtoBuffer 解压缩配置
const server = new Ssocket({
/**protos 开启压缩并配置:注 当数据量大于 128 字节的时候自动开启 GZIP 压缩 */
protos:{ // 非必传
// 配置请求编码
request:{
"test":{
/**
* [required单字段|repeated重复字段|message自定义结构] [string|uint[8|16|32]|float|double] fieldname: 序号同级唯一
*/
"required string username": 0,
}
},
// 配置响应编码
response:{
"test":{
/**
* [required单字段|repeated重复字段|message自定义结构] [string|uint[8|16|32]|float|double] fieldname: 序号同级唯一
*/
"required string username": 0,
"required uint8 age": 1,
"required uint32 amount": 2,
"required string avatar": 3,
"required Data test": 4,
"message Data": {
"required string usernmae": 0,
"repeated List list": 1,
"message List": {
"required uint32 id": 0,
},
},
}
}
}
})
server.router.ONPath("test", function(ctx, next){
console.log(ctx.data)// {
// username:"测试账号",
// }
return {
username: `登录成功,欢迎${ctx.data.usernmae}`
}
})
// 前端
client.request("test", {
username:"测试账号",
}, function(ctx){
console.log("返回状态", ctx.status)// 200
console.log("返回说明", ctx.msg)// ok
console.log("返回数据", ctx.data) // { username:"登录成功,欢迎测试账号" }
})
服务端对象事件控制
server.on("connection", function(client/**SWebSocket */, request/**IncomingMessage */){
console.lof("接收到一个客户端连接", client.getid())
})
server.on("reconnection", function(client/**SWebSocket */, id/**client_id*/){
console.lof("一个客户端重连成功", client.getid())
})
server.on("route-error", function(ctx, err){
console.log("路由报错", ctx, err)
})
server.on("close", function(client_id, code, reason){
console.log("连接关闭", client_id, code, reason)
})
路由事件控制
const Ssocket = require("ssocket").default;
const { Router, Code, CODE } = require("ssocket");
const server = new Ssocket({ port:8080 })
// 扩展错误码
Code.expandStatusCode(201, "没有提交【username】字段")
// 创建路由对象
const main = new Router();
const user = new Router();
const login = new Router();
// 事件中间件拦截校验请求参数
login.USEMiddleware(function(ctx, next){
// 校验失败返回错误码
if(!ctx.data.username) return CODE[201];
// 校验成功,注:所有的中间件必须拥有返回值,没有返回值就返回 next()
return next();
})
// 在 /login 路径下注册一个请求处理方法
login.ONPath("/login", function(ctx, next){
return {
username: `登录成功,欢迎${ctx.data.usernmae}`
}
})
// 将登陆路由注册到 /user 路由下
user.USEPathMiddleware("/user", login.routes)
main.USEPathMiddleware("user", user.routes);
// 将 main 路由对象注册到 Socket 服务中
server.router.USEMiddleware(main.routes);
// 前端
client.request("user/user/login"/*由上面路由对象会组成这个路由路径*/, { username:"小明" }, function(ctx){
console.log("返回状态", ctx.status)// 200/201
console.log("返回说明", ctx.msg)// ok/没有提交【username】字段
console.log("返回数据", ctx.data) // { username:"登录成功,欢迎小明" }
})
消息控制
login.ONPath("/login", async function(ctx, next){
ctx.socket // 在上下文中会注入 SWebSocket 对象
ctx.app // 在上下文中会注入 Application 对象,这个对象等于上面的 Ssocket
// 加入房间
ctx.app.join(ctx.socket_id, "roomid_123")
//离开房间
ctx.app.leave(ctx.socket_id, "roomid_123")
// 获取所有的房间ID
let rooms = await ctx.app.getRoomall()
// 根据 客户端ID 获取所在的所有房间ID
let rooms = await ctx.app.getRoomidByid(ctx.socket_id)
// 根据房间号获取所有的客户端ID
let clientids = await ctx.app.getClientidByroom("roomid_123")
// 获取所有的房间总数
let room_count = await ctx.app.getAllRoomcount()
// 获取房间内人员数量
let client_count = await ctx.app.getRoomsize("roomid_123")
// 判断客户端是否存在啊某个房间
let flog = await ctx.app.hasRoom(ctx.socket_id, "roomid_123")
// 单独向某条连接发送消息
ctx.app.sendSocketMessage(ctx.socket_id, "user.user.login", { username:`登录成功,欢迎${ctx.data.usernmae}` })
// 单独向某个房间发送消息
ctx.app.sendRoomMessage("roomid_123", "user.user.login", { username:`登录成功,欢迎${ctx.data.usernmae}` })
// 向所有连接发送广播消息
ctx.app.sendBroadcast("user.user.login", { username:`登录成功,欢迎${ctx.data.usernmae}` })
return {
username: `登录成功,欢迎${ctx.data.usernmae}`
}
})
// 前端
client.on("user.user.login", function(ctx){
console.log("返回状态", ctx.status)// 200
console.log("返回说明", ctx.msg)// ok
console.log("返回数据", ctx.data) // { username:"登录成功,欢迎小明" }
})
客户端对象事件控制
server.on("connection", function(client/**SWebSocket */, request/**IncomingMessage */){
console.log("接收到一个客户端连接", client.getid())
client.on("close", function(id, code, reason){
console.log("连接断开, 客户端ID", id)
console.log("断开代码", code)
console.log("断开原因", reason)
})
client.on("shakehands", function(status){
console.log("握手状态", status)// 2握手成功|3握手完毕
})
client.on("connection", function(id){
console.log("握手完毕,连接成功, 客户端ID", id)
})
client.on("reconnection", function(id){
console.log("重新连接成功, 客户端ID", id)
})
client.on("ping", function(client_now_time){
console.log("收到客户端一个心跳事件, 此时该客户端当前时间是", client_now_time)
})
client.on("pong", function(){
console.log("服务器回复一个心跳响应事件")
})
})