drogonframework / drogon

Drogon: A C++14/17/20 based HTTP web application framework running on Linux/macOS/Unix/Windows
MIT License
11.44k stars 1.1k forks source link

Add REST API to websocketserver sample... #998

Closed Aventun closed 3 years ago

Aventun commented 3 years ago

Hi, I am very new to drogon lib (it seems excellent anyway) and in these first days I have been trying to create REST API. Usually Iwrite a class that inherits from HttpController and I add the METHOD_LIST_BEGIN block and its done.

Now I was trying the websocketserver sample to add a HTTP POST CALL in order to receive data from HTTP POST and then publish that data into a websocket room. But now the websocket sample uses the WS_PATH_LIST_BEGIN block and when I add the:

METHOD_LIST_BEGIN
    ADD_METHOD_TO(WebSocketChat::getHello, "/hello", Get); 
METHOD_LIST_END

block, the compiler complains...

Can we mix METHOD_LIST_BEGIN and WS_PATH_LIST_BEGIN in the same drogon::WebSocketController<> class?

Is there any sample that mixes REST API and websockets?

Any guidance would be very appreciated.

Thanks Av

class WebSocketChat : public drogon::WebSocketController<WebSocketChat>
{
  public:
    virtual void handleNewMessage(const WebSocketConnectionPtr &,std::string &&,const WebSocketMessageType &) override;
    virtual void handleConnectionClosed(const WebSocketConnectionPtr &) override;
    virtual void handleNewConnection(const HttpRequestPtr &,const WebSocketConnectionPtr &) override;
    WS_PATH_LIST_BEGIN
    WS_PATH_ADD("/chat", Get);
    WS_PATH_LIST_END

    METHOD_LIST_BEGIN
    ADD_METHOD_TO(WebSocketChat::getHello, "/hello", Get); 
    METHOD_LIST_END

  private:
    PubSubService<std::string> chatRooms_;  //tipo de mensagem=>std::string

    //bool  ValidUser(std::string str_token);
};
marty1885 commented 3 years ago

The answer is you can't add a REST API endpoint to a WebSocket controller. Well, they speak different protocols. What you want to do in this case is to have 2 controllers. One WebSocketController and one HttpController. And then expose some static member variables so you could communicate between them. For example:

First, mark chatRooms_ as a public static member. (There's other ways to do it. But this is the easiest)

public:
    static PubSubService<std::string> chatRooms_;

Then make a new HttpController for your API endpoint.

#include "WebSocketChat.h" // include WebSocketChat so could be used later
#include <drogon/HttpController>

class MyAPI : public drogon::HttpController<MyAPI>
{
public:
    void sayHello(const HttpRequestPtr& req,
                       std::function<void (const HttpResponsePtr &)> &&callback)
    {
        // Now you can publish data here!
        WebSocketChat::chatRooms_.publish("chat_room_name", "hello!");
    }

    METHOD_LIST_BEGIN
        ADD_METHOD_TO(WebSocketChat::sayHello, "/hello", Post); 
    METHOD_LIST_END
};

You don't have to worry that there could be multiple instances of WebSocketChat. Drogon internally enforces only one could evert spawn.

Aventun commented 3 years ago

Unfortunatly, WebSocketChat::chatRooms_ raises a compiler issue:

undefined reference to "WebSocketChat::chatRooms_[abi:cxx11]"

even inside WebSocketChat class.

I have solely a .cc file so:

inline keyword does the trick!

Thank you very much

18871434218 commented 10 months ago

请问你内部 怎么调用和处理的,改为public: static PubSubService chatRooms_; 之后,编译出错