在制作萌梦聊天室过程中学习到的一些NodeBB论坛的知识



  • 我们认为,制作萌梦聊天室这样的,具有挑战性的事情,很少有相关的参考资料,因此,我将我们开发的困难记录在本论坛中,以免忘记。👧🏻 🎅



  • 有关会话共享的一些资料。会话共享可能在制作手机APP和我们的论坛共通方面具有一定的作用。先记下来:这里



  • 现在遇到的问题是,发送NodeBB获取聊天总数的socket.io消息,没有收到回应。这里我怀疑是没有通过它的用户验证模块。可能的解决办法就是调试一下NodeBB后端的代码,来判断是否是哪个位置阻断了获取socket.io消息的获取。



  • 有迹象表明,NodeBB在处理登录的时候,是不走socket.io的,而是像平常一样走form表单提交。



  • @jiangcaiyang

    一些长连接就需要走 socket.io,例如一些短而多的请求一般由 http 来处理。



  • 这样的话,我们可能会调试socket.io服务端的上一层逻辑层,如何处理event:unread.updateChatCount这个事件的。



  • QtDream/src/socket.io/user.js代码中,我们发现,它们将要导出的名称命名为SocketUser了。意思就是这样的用户对象走的都是socket.io这一套。



  • 在服务端的这段代码中可以看到,NodeBB对socket.io设定了UID
    0_1466933289831_upload-2e64688a-0512-42a6-b894-435d494f90c5
    这样的话,在下面这段代码中就可以判断当拥有了UID后才可以进行获取未读消息的逻辑。
    0_1466933369079_upload-705759c5-8e5b-479e-9966-47000320cada



  • ❓ 疑问
    调试NodeBB的时候,为什么服务端可以检测出用户的ID出来?难道socket.io的sid(会话ID)和用户登录的sessionID以及用户的ID存在着映射的关系么?我要好好调查一下。



  • 找到了一个线索:那就是当登录了之后,每一个类似的主题,在头部都有一个内联的Javascript脚本。这个脚本呢,存储的是用户的一些基本信息,登录后和登录前数据是不一样的。
    0_1466997279254_upload-e4f4e547-e767-4aca-863c-912e7d4d61b8



  • 花了很长的时间将socket.io的基本代码实现重构了一遍。其实这是第三遍重构了,这里克服了很多C++/Javascript语法不一致的困难,已经顺利地运行了,和普通的socket.io的效果一致。这里呢,我们要开始研究上层的逻辑,究竟如何才能顺利地获取到我们想要的聊天信息。



  • 根据几次前的思路,我们将本地客户端中html中嵌入的app.user的数据写死到我们的QML代码中,然后通过传入预设好的uid来发送给服务端user.getUnreadCounts消息,最终获取到返回的消息。



  • 虽然socket.io的底层已经被我用C++改写并且实现了,但是我发现,如果没有获取一个合适的登录会话ID,还是无法执行类似获取即时消息个数这样的方法的。也就是说,我们在执行一个需要用户登录参与的操作时,一定要执行一次用户登录操作才行。



  • 我发现NodeBB在用户登录后,会在本地Cookies中存放一个键值对(express.sid)。这个值一般是97字节的无序字符串。



  • NodeBB用户在登录的时候,会调用jQuery的一个非常常用的函数:formEl.ajaxSubmit。有关这个函数的用法,相信搜索会有很多好的结果。接下来遇到的问题就是,ajaxSubmit这个函数依赖一个变量:x-csrf-token。这个变量需要依赖Node.js的csrf库。我还需要调查一下这个库,究竟是如何生成的,有没有什么规律。



  • 后面发现,原来我们的第一版登录的逻辑已经实现了登录的逻辑!
    但是后面想起来,还缺少一些必要的组成部分,那就是有关会话的注册(setup)和撤销(revoke)!这非常重要,对于我们以后聊天功能的整合可以说是非常重要的,我们将在下一版程序中进行这方面的研究和解决。



  • 虽然能够顺利登录,但是在用socket.io调用user.getUnreadCounts事件时,会出现{"message":"[[error:invalid-session]]"}这样的消息。定位到源码,发现这里被拒绝了:
    0_1467558948132_upload-714acdf1-73ad-4d98-9784-f0237081ee5e
    看来我们要想一个办法,模仿Web客户端那样登录,并且能够发送类似Web客户端发送的cookie,这样就有可能避开这个错误。



  • NodeBB论坛在Web客户端访问的时候设置了一个会话ID。浏览器如果可以支持查看cookie的话,可以看到这个会话ID的键是express.sid,值是一个32字节的Hash值,究竟是SHA1还是其他的Hash值我还不是很清楚,还需要详细调查一下。👀



  • 今天发现这样一个现象。凡是游客访问NodeBB论坛,并且管理员没有启用游客访问,那么没有客户端的SocketIO,也就是说,服务端的SocketIO也会根据客户端的request来判定是否是启用了游客访问。如果没有request对象,那么会报[[error:not-authorized]]错误。详情可以看这里的代码:
    0_1467700251091_upload-39717b87-0049-4ebc-93cd-98fbe0718818



  • 聊天室开发有重大的进展!
    这边可以顺利地登录并且可以顺利地获取未读取的聊天个数的数据了!
    接下来上层代码可以开始开工了。


Log in to reply
 

走马观花

最近的回复

  • 诶 没有Linux吗??

    read more
  • 萌梦 男孩,女孩,和蛋

    menghome.png

    read more
  • 设计模式-工厂模式

    使用qt/qml来演示设计模式效果,便于学习理解

    1)定义创建对象的接口,封装对象的创建
    2)使具体化类的工作延迟到工厂子类中

    bg.png
    image.png

    1. 工厂类

    createProduct使用了参数来选择要创建哪个产品

    #ifndef FACTORY_H #define FACTORY_H #include <QObject> class Product; class QString; class Factory: public QObject { Q_OBJECT public: virtual ~Factory() = 0; virtual Product* createProduct(QString type) = 0; protected: Factory(); }; class ConcreteFactory: public Factory { Q_OBJECT public: ~ConcreteFactory(); ConcreteFactory(); public slots: Product* createProduct(QString type); }; #endif // FACTORY_H #include "factory.h" #include "product.h" #include <QtQml/qqml.h> Factory::~Factory() { } Factory::Factory() { qmlRegisterType<Product>("Product", 1, 0, "Product"); } ConcreteFactory::~ConcreteFactory() { } ConcreteFactory::ConcreteFactory() { } Product *ConcreteFactory::createProduct(QString type) { if(type == "boy") return static_cast<Product *>(new ConcreteProduct1()); else if(type == "girl") return static_cast<Product *>(new ConcreteProduct2()); return static_cast<Product *>(new ConcreteProduct1()); } 2 产品类

    一个产品是萌梦男,一个产品是萌梦女

    #ifndef PRODUCT_H #define PRODUCT_H #include <QObject> class Product: public QObject { Q_OBJECT public: virtual ~Product() = 0; Q_PROPERTY(QString icon READ icon NOTIFY iconChanged) QString m_icon; QString icon() const { return m_icon; } signals: void iconChanged(QString icon); protected: Product(); signals: public slots: }; class ConcreteProduct1: public Product { Q_OBJECT public: ~ConcreteProduct1(); ConcreteProduct1(); }; class ConcreteProduct2: public Product { Q_OBJECT public: ~ConcreteProduct2(); ConcreteProduct2(); }; #endif // PRODUCT_H #include "product.h" Product::~Product() { } Product::Product() { } ConcreteProduct1::~ConcreteProduct1() { } ConcreteProduct1::ConcreteProduct1() { m_icon = "qrc:/images/boy.png"; } ConcreteProduct2::~ConcreteProduct2() { } ConcreteProduct2::ConcreteProduct2() { m_icon = "qrc:/images/girl.png"; } 3. main.qml

    使用timer,canvas,listview等实现一个自动化生产的动画效果

    源代码

    Fork me on Gitee

    read more
  • blender建模 章鱼
    捕获2.PNG 😵

    read more

关注我们

微博
QQ群