mirror of
https://github.com/idolpx/libMeatloaf.git
synced 2025-12-06 04:38:49 -05:00
177 lines
5.2 KiB
C++
177 lines
5.2 KiB
C++
// WS:// - WebSockets
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
|
|
// https://en.wikipedia.org/wiki/WebSocket
|
|
//
|
|
|
|
#ifndef MEATLOAF_SCHEME_WS
|
|
#define MEATLOAF_SCHEME_WS
|
|
|
|
#include "meat_io.h"
|
|
#include "../../include/global_defines.h"
|
|
|
|
#include "string_utils.h"
|
|
|
|
/********************************************************
|
|
* Streams
|
|
********************************************************/
|
|
|
|
class CSIOStream: public MStream {
|
|
public:
|
|
CSIOStream(MFile* file, bool isServer) : m_isServer(isServer) {
|
|
// drop ws:// from url and it's OK!
|
|
address = websockets::WSInterfaceString(mstr::drop(file->url, 5).c_str());
|
|
if(!file->port.empty())
|
|
port = std::stoi(file->port);
|
|
}
|
|
|
|
~CSIOStream() {
|
|
close();
|
|
}
|
|
|
|
void close() override {
|
|
client.close();
|
|
}
|
|
|
|
bool open() override {
|
|
if(m_isServer) {
|
|
server.listen(port);
|
|
client = server.accept();
|
|
prepareClientCallbacks();
|
|
_is_open = server.available();
|
|
}
|
|
else {
|
|
prepareClientCallbacks();
|
|
_is_open = client.connect(address);
|
|
// waring - client->poll() required to keep it working!
|
|
}
|
|
|
|
return _is_open;
|
|
};
|
|
|
|
// MStream methods
|
|
uint32_t position() override { return 0; };
|
|
uint32_t available() override { return INT_MAX; };
|
|
bool isOpen() { return _is_open; };
|
|
bool seek(uint32_t pos) { return false; };
|
|
uint32_t size() { return INT_MAX; };
|
|
|
|
uint32_t read(uint8_t* buf, uint32_t size) override {
|
|
//auto msg = client.readBlocking(); // we don't want to block. We'll store a message from callback in msg
|
|
|
|
if(!_is_open)
|
|
return 0;
|
|
|
|
if(!lastMsg.isEmpty()) {
|
|
auto maxLen = (size < lastMsg.length()) ? size : lastMsg.length();
|
|
strncpy((char *)buf, lastMsg.c_str(), maxLen);
|
|
Debug_printv("Sending last msg and polling!");
|
|
lastMsg = "";
|
|
client.poll();
|
|
return maxLen;
|
|
}
|
|
else {
|
|
Debug_printv("Polling!");
|
|
client.poll();
|
|
return 0;
|
|
}
|
|
}
|
|
size_t write(const uint8_t *buf, size_t size) override {
|
|
if(!_is_open)
|
|
return 0;
|
|
|
|
websockets::WSInterfaceString message((char *)buf);
|
|
client.send(message);
|
|
return message.length();
|
|
}
|
|
|
|
protected:
|
|
websockets::WSInterfaceString address; // format: www.myserver.com:8080
|
|
uint16_t port = 80;
|
|
bool _is_open;
|
|
bool m_isServer;
|
|
websockets::WebsocketsClient client;
|
|
websockets::WebsocketsServer server;
|
|
websockets::WSInterfaceString lastMsg;
|
|
|
|
void prepareClientCallbacks() {
|
|
client.onMessage([this](websockets::WebsocketsMessage msg){
|
|
//
|
|
// I think this get called only if you do client.poll()
|
|
//
|
|
Debug_printv("Got message: %s", msg.data().c_str());
|
|
|
|
if(msg.isText()) {
|
|
//(*msgPtr) = (std::string)msg.data();
|
|
this->lastMsg = msg.data();
|
|
}
|
|
});
|
|
|
|
client.onEvent([this](websockets::WebsocketsEvent event, String data) {
|
|
if(event == websockets::WebsocketsEvent::ConnectionOpened) {
|
|
Debug_printv("Socket Connnection Opened");
|
|
this->_is_open = true;
|
|
} else if(event == websockets::WebsocketsEvent::ConnectionClosed) {
|
|
Debug_printv("Socket Connnection Closed");
|
|
this->_is_open = false;
|
|
} else if(event == websockets::WebsocketsEvent::GotPing) {
|
|
Debug_printv("Got a Ping!");
|
|
} else if(event == websockets::WebsocketsEvent::GotPong) {
|
|
Debug_printv("Got a Pong!");
|
|
}
|
|
});
|
|
};
|
|
};
|
|
|
|
/********************************************************
|
|
* File implementations
|
|
********************************************************/
|
|
|
|
class WSFile: public MFile {
|
|
|
|
public:
|
|
WSFile(std::string path): MFile(path) {};
|
|
|
|
bool isDirectory() override { return false; }
|
|
MStream* getSourceStream(std::ios_base::openmode mode=std::ios_base::in) override {
|
|
// input stream = SERVER socket
|
|
return new CSIOStream(this, true);
|
|
};
|
|
time_t getLastWrite() override { return 0; };
|
|
time_t getCreationTime() override { return 0; };
|
|
bool rewindDirectory() override { return false; };
|
|
MFile* getNextFileInDir() override { return nullptr; };
|
|
bool mkDir() override { return false; };
|
|
bool exists() override { return false; };
|
|
size_t size() override { return 0; };
|
|
bool remove() override { return false; };
|
|
bool rename(std::string dest) { return false; };
|
|
MStream* getDecodedStream(std::shared_ptr<MStream> src) {
|
|
return nullptr;
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/********************************************************
|
|
* FS
|
|
********************************************************/
|
|
|
|
class WSFileSystem: public MFileSystem
|
|
{
|
|
MFile* getFile(std::string path) override {
|
|
return new WSFile(path);
|
|
}
|
|
|
|
bool handles(std::string name) {
|
|
std::string pattern = "ws:";
|
|
return mstr::equals(name, pattern, false);
|
|
}
|
|
public:
|
|
WSFileSystem(): MFileSystem("ws") {};
|
|
};
|
|
|
|
|
|
|
|
#endif /* MEATLOAF_SCHEME_WS */
|