wechaty / puppet-wechat4u

Wechat4u Puppet for Wechaty
https://www.npmjs.com/package/wechaty-puppet-wechat4u
Apache License 2.0
114 stars 38 forks source link

调用stop方法后会报错Cannot read properties of undefined (reading 'start') #77

Open hilaryfrank opened 7 months ago

hilaryfrank commented 7 months ago

异常错误

启动bot后。如果调用stop方法停止bot。此时会报错:Cannot read properties of undefined (reading 'start')。日志如下: TypeError: Cannot read properties of undefined (reading 'start') at Wechat. (/Users/cdliuhaibo/bocai/learn/code/bocai/chatbot/node_modules/wechaty-puppet-wechat4u/src/puppet-wechat4u.ts:365:21) {stack: "TypeError: Cannot read properties of undefined (re…ty-puppet-wechat4u/src/puppet-wechat4u.ts:365:21)", message: "Cannot read properties of undefined (reading 'start')"}

根因分析

看了下源码,在puppet-wechat4u.ts中的如下代码this.wechat4u.start会报错:

wechat4u.on('logout', async () => {
      log.silly('PuppetWechat4u', 'initHookEvents() wechat4u.on(logout)')
      if (this.isLoggedIn) {
        await this.logout()
      }
      // 清除数据
      await this.memory.delete(MEMORY_SLOT_NAME)
      await this.memory.save()
      this.wechat4u.start()
    })

原因应该是因为this.wechat4u这个对象为undefined。很好奇,在logout之后为什么还要调用 this.wechat4u.start()呢?

至于这里的this.wechat4u这个对象为undefined的原因,我大致看了下。是因为当我们调用stop方法的时候,会触发puppet-wechat4u.ts中的onStop方法。这个方法内容如下:

override async onStop (): Promise<void> {
    log.verbose('PuppetWechat4u', 'onStop()')

    this.wechat4u.stop()
    this.wechat4u = undefined
    if (this._heartBeatTimer) {
      clearTimeout(this._heartBeatTimer)
      this._heartBeatTimer = undefined
    }
  }

这里首先调用了this.wechat4u.stop(),然后就将就将this.wechat4u设置为了undefined。问题就在于this.wechat4u.stop()方法最终会触发logout操作。其代码如下(wecaht.js > stop):

stop () {
    debug('登出中...')
    clearTimeout(this.retryPollingId)
    clearTimeout(this.checkPollingId)
    this.logout()
    this.state = this.CONF.STATE.logout
    this.emit('logout')
  }

这里触发了logout后,最终会触发一个logout事件。该事件会触发到puppet-wechat4u.ts中的logout监听(前面抛异常的位置)。代码如下,其中使用到了this.wechat4u,但这个对象已经在stop方法中被设置为undefined了。所以最终会报异常。

wechat4u.on('logout', async () => {
      log.silly('PuppetWechat4u', 'initHookEvents() wechat4u.on(logout)')
      if (this.isLoggedIn) {
        await this.logout()
      }
      // 清除数据
      await this.memory.delete(MEMORY_SLOT_NAME)
      await this.memory.save()
      this.wechat4u.start()
    })

问题?

麻烦看下, 1、这个是问题还是我使用不对? 还是什么原因呢? 2、为什么logout后,还要启动一下wechat4u呢?

huan commented 6 months ago

This issue is very high-quality; thanks for reporting it by reading the source code, @hilaryfrank! I hope you can learn by digging deeper and finally solving the problem.

Please join our Wechaty Discord service if you haven't yet: https://discord.gg/7q8NBZbQzt

hzb888 commented 4 months ago

Hello, I have the same problem. Did you solve it?