vendor/webman/push/src/push-uniapp.js
webman-push自带的这个 push-uniapp.js直接使用__ajax()这里会报错,让gpt帮我改了一下。
我看它有些函数缺失了,不过能用!
有需要的直接拿用吧。
有大佬觉得不妥的,可以补全一下啊!
/**************** Dispatcher ****************/
function Dispatcher() {
this.callbacks = {};
}
Dispatcher.prototype.on = function (event, fn) {
(this.callbacks[event] = this.callbacks[event] || []).push(fn);
};
Dispatcher.prototype.off = function (event, fn) {
if (!this.callbacks[event]) return;
this.callbacks[event] = this.callbacks[event].filter(f => f !== fn);
};
Dispatcher.prototype.emit = function (event, data) {
(this.callbacks[event] || []).forEach(fn => fn(data));
};
/**************** Push ****************/
function Push(options) {
this.doNotConnect = 0;
options = options || {};
options.heartbeat = options.heartbeat || 25000;
options.pingTimeout = options.pingTimeout || 10000;
this.config = options;
this.uid = 0; // 补充缺失的uid属性
this.channels = {};
this.connection = null;
this.pingTimeoutTimer = null;
this.checkoutPingTimer = null;
Push.instances.push(this);
this.createConnection();
}
Push.instances = [];
/**************** 心跳 ****************/
Push.prototype.checkoutPing = function () {
let _this = this;
clearTimeout(_this.checkoutPingTimer);
_this.checkoutPingTimer = setTimeout(() => {
if (_this.connection.state === 'connected') {
_this.connection.send(JSON.stringify({
event: "pusher:ping",
data: {}
}));
clearTimeout(_this.pingTimeoutTimer);
_this.pingTimeoutTimer = setTimeout(() => {
_this.connection.closeAndClean();
!_this.connection.doNotConnect && _this.connection.waitReconnect();
}, _this.config.pingTimeout);
}
}, _this.config.heartbeat);
};
/**************** 连接 ****************/
Push.prototype.createConnection = function () {
let _this = this;
this.connection = new Connection({
url: this.config.url,
app_key: this.config.app_key,
onOpen() {},
onMessage(res) {
clearTimeout(_this.pingTimeoutTimer);
let params;
try {
params = JSON.parse(res.data);
} catch {
return;
}
let event = params.event;
let channel_name = params.channel;
if (event === 'pusher:pong') {
_this.checkoutPing();
return;
}
if (event === 'pusher:error') {
console.error(params.data);
return;
}
let data = {};
try {
data = typeof params.data === 'string'
? JSON.parse(params.data)
: params.data;
} catch {}
if (event === 'pusher:connection_established') {
_this.connection.socket_id = data.socket_id;
_this.connection.updateState('connected');
_this.subscribeAll();
_this.checkoutPing();
return;
}
if (event === 'pusher_internal:subscription_succeeded') {
let ch = _this.channels[channel_name];
if (ch) {
ch.subscribed = true;
ch.processQueue();
ch.emit('pusher:subscription_succeeded');
}
return;
}
// 添加对pusher_internal事件的处理
if (event.indexOf('pusher_internal') !== -1) {
console.log("Event '"+event+"' not implement");
return;
}
let ch = _this.channels[channel_name];
if (ch) {
ch.emit(event, data);
}
},
onClose() {
_this.resetSubscribe();
},
onError() {
_this.resetSubscribe();
}
});
};
/**************** API 补回 ****************/
Push.prototype.channel = function (name) {
return this.channels[name];
};
Push.prototype.allChannels = function () {
return this.channels;
};
/**************** 订阅恢复 ****************/
Push.prototype.resetSubscribe = function () {
for (let k in this.channels) {
this.channels[k].subscribed = false;
}
};
Push.prototype.subscribeAll = function () {
if (this.connection.state !== 'connected') return;
for (let name in this.channels) {
this.channels[name].processSubscribe();
}
};
/**************** 订阅 ****************/
Push.prototype.subscribe = function (name) {
if (this.channels[name]) return this.channels[name];
// 添加对presence-频道的支持
if (name.indexOf('presence-') === 0) {
return createPresenceChannel(name, this);
}
let ch = name.startsWith('private-') || name.startsWith('presence-')
? createPrivateChannel(name, this)
: createChannel(name, this);
this.channels[name] = ch;
return ch;
};
/**************** 取消订阅 ****************/
Push.prototype.unsubscribe = function (name) {
if (!this.channels[name]) return;
if (this.connection.state === 'connected') {
this.connection.send(JSON.stringify({
event: "pusher:unsubscribe",
data: { channel: name }
}));
}
delete this.channels[name];
};
Push.prototype.unsubscribeAll = function () {
for (let name in this.channels) {
this.unsubscribe(name);
}
};
/**************** 断开 ****************/
Push.prototype.disconnect = function () {
this.doNotConnect = 1;
this.unsubscribeAll();
clearTimeout(this.checkoutPingTimer);
clearTimeout(this.pingTimeoutTimer);
if (this.connection) {
this.connection.doNotConnect = 1;
this.connection.closeAndClean();
}
};
/**************** Channel ****************/
function createChannel(name, push) {
let ch = new Channel(push.connection, name);
ch.subscribeCb = () => {
push.connection.send(JSON.stringify({
event: "pusher:subscribe",
data: { channel: name }
}));
};
ch.processSubscribe();
return ch;
}
function createPrivateChannel(name, push) {
let ch = new Channel(push.connection, name);
ch.subscribeCb = () => {
if (!push.connection.socket_id) {
setTimeout(() => ch.processSubscribe(), 300);
return;
}
let auth = push.config.auth;
let headers = auth.headers || {};
// 关键修复:支持 function
if (typeof headers === 'function') {
headers = headers();
}
// 兜底,防止 undefined / null / string
if (Object.prototype.toString.call(headers) !== '[object Object]') {
headers = {};
}
uni.request({
url: typeof auth === 'string' ? auth : auth.url,
method: 'POST',
data: {
channel_name: name,
socket_id: push.connection.socket_id
},
header: headers,
success: (res) => {
let data = res.data;
if (data && data.data) {
data = data.data;
}
if (!data || !data.auth) {
console.error('[Push] auth失败', res.data);
return;
}
data.channel = name;
push.connection.send(JSON.stringify({
event: "pusher:subscribe",
data: data
}));
}
});
};
ch.processSubscribe();
return ch;
}
// 补充缺失的createPresenceChannel函数
function createPresenceChannel(channel_name, push) {
return createPrivateChannel(channel_name, push);
}
/**************** Connection ****************/
function Connection(options) {
this.options = options;
this.state = 'initialized';
this.socket_id = null;
this.doNotConnect = 0;
this.reconnectInterval = 1000;
this.reconnectTimer = null;
this.dispatcher = new Dispatcher();
this.connect();
}
Connection.prototype.updateState = function (state) {
this.state = state;
this.dispatcher.emit('state_change', state);
};
Connection.prototype.connect = function () {
let _this = this;
uni.connectSocket({
url: this.options.url + '/app/' + this.options.app_key,
});
uni.onSocketOpen((res) => {
if (_this.doNotConnect) return;
_this.options.onOpen && _this.options.onOpen(res);
});
uni.onSocketMessage(this.options.onMessage);
uni.onSocketClose(() => {
_this.updateState('disconnected');
!_this.doNotConnect && _this.waitReconnect();
_this.options.onClose && _this.options.onClose();
});
uni.onSocketError(() => {
_this.updateState('disconnected');
!_this.doNotConnect && _this.waitReconnect();
_this.options.onError && _this.options.onError();
});
};
Connection.prototype.waitReconnect = function () {
let _this = this;
clearTimeout(this.reconnectTimer);
this.reconnectTimer = setTimeout(() => {
_this.connect();
}, this.reconnectInterval);
this.reconnectInterval = Math.min(this.reconnectInterval * 2, 5000);
};
Connection.prototype.send = function (data) {
if (this.state !== 'connected') return;
uni.sendSocketMessage({ data });
};
Connection.prototype.closeAndClean = function () {
uni.closeSocket();
this.updateState('disconnected');
};
Connection.prototype.close = function(){
this.updateState('disconnected');
uni.closeSocket();
}
/**************** Channel ****************/
function Channel(connection, name) {
this.connection = connection;
this.channelName = name;
this.subscribed = false;
this.queue = [];
this.dispatcher = new Dispatcher();
}
Channel.prototype.on = function (event, fn) {
this.dispatcher.on(event, fn);
};
Channel.prototype.off = function (event, fn) {
this.dispatcher.off(event, fn);
};
Channel.prototype.emit = function (event, data) {
this.dispatcher.emit(event, data);
};
Channel.prototype.processSubscribe = function () {
if (this.connection.state !== 'connected') return;
this.subscribeCb && this.subscribeCb();
};
Channel.prototype.processQueue = function () {
if (!this.subscribed) return;
this.queue.forEach(fn => fn());
this.queue = [];
};
Channel.prototype.trigger = function (event, data) {
if (!event.startsWith('client-')) {
throw new Error("Event must start with client-");
}
this.queue.push(() => {
this.connection.send(JSON.stringify({
event,
data,
channel: this.channelName
}));
});
this.processQueue();
};
/**************** 网络恢复 ****************/
uni.onNetworkStatusChange(function (res) {
if (res.isConnected) {
Push.instances.forEach(p => {
let con = p.connection;
con.reconnectInterval = 1000;
if (con.state !== 'connected') {
con.connect();
}
});
}
});
export default Push;
使用的的话是这样:
manager.js
import Push from './push.js';
class PushManager {
constructor() {
this.instance = null;
this.userId = null;
this.userChannel = null;
}
/**
* 登录后绑定用户
*/
bindUser(userId) {
if (!userId)
return;
// 登录后才初始化
if (!this.instance) {
this.instance = new Push({
url: 'ws://127.0.0.1:3131',
app_key: '55f964f420b0c5d98fcc38a555c4aac8',
auth: {
url: 'http://localhost:8787/plugin/webman/push/auth',
// 用函数,保证每次都是最新 token
headers: () => ({
token: uni.getStorageSync('token'),
}),
},
});
console.log('[Push] 登录后初始化');
}
// 防重复绑定
if (this.userId === userId)
return;
this.userId = userId;
// 清理旧频道
if (this.userChannel) {
this.userChannel.off('message');
this.userChannel = null;
}
// 订阅新频道
// this.userChannel = this.instance.subscribe(`user-${userId}`);
// console.log(`[Push] 已订阅 user-${userId}`);
// 订阅私有频道
this.userChannel = this.instance.subscribe(`private-user-${userId}`);
console.log(`[Push] 已订阅 private-user-${userId}`);
this._bindEvents();
}
_bindEvents() {
// 核心:统一出口
this._lastNotifyTime = 0;
this.userChannel.on('message', (data) => {
const now = Date.now();
if (now - this._lastNotifyTime < 1000) {
return; // 1秒内不重复弹
}
this._lastNotifyTime = now;
console.log('[PushManager] 收到消息喽:', data);
// 防止空数据
const content = data?.content || '你有一条新消息';
uni.showModal({
title: '消息提醒',
content,
showCancel: false,
});
});
}
/**
* 断开(退出登录时)
*/
disconnect() {
if (this.instance) {
this.instance.disconnect();
this.instance = null;
}
this.userId = null;
this.userChannel = null;
}
}
export default new PushManager();
关于缺少的几个函数,
GPT是这么说的:让我详细分析这5个缺失的函数是否会影响功能使用:
__ajax函数缺失 - 不影响功能使用
__extends函数缺失 - 不影响功能使用
Collections工具函数缺失 - 不影响功能使用
Connection.prototype.connect方法实现差异 - 不影响功能使用
formatParams函数缺失 - 不影响功能使用
结论:不补齐这5个函数不会影响核心功能使用,优化后的代码已经能够正常工作,且在某些方面还进行了改进。这些缺失的函数都是辅助性质的,主要作用是提供额外的工具或兼容性支持,但不是核心功能所必需的。