Skip to content

Commit b28adcc

Browse files
v0.7.7
1 parent 9a1caf6 commit b28adcc

File tree

9 files changed

+112
-155
lines changed

9 files changed

+112
-155
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<img src="https://static.wikia.nocookie.net/arnelify/images/c/c8/Arnelify-logo-2024.png/revision/latest?cb=20240701012515" style="width:336px;" alt="Arnelify Logo" />
22

3-
![Arnelify Server for Python](https://img.shields.io/badge/Arnelify%20Server%20for%20Python-0.7.5-yellow) ![C++](https://img.shields.io/badge/C++-2b-red) ![G++](https://img.shields.io/badge/G++-14.2.0-blue) ![Python](https://img.shields.io/badge/Python-3.11.2-blue) ![Nuitka](https://img.shields.io/badge/Nuitka-2.6.4-blue)
3+
![Arnelify Server for Python](https://img.shields.io/badge/Arnelify%20Server%20for%20Python-0.7.7-yellow) ![C++](https://img.shields.io/badge/C++-2b-red) ![G++](https://img.shields.io/badge/G++-14.2.0-blue) ![Python](https://img.shields.io/badge/Python-3.11.2-blue) ![Nuitka](https://img.shields.io/badge/Nuitka-2.6.4-blue)
44

55
## 🚀 About
66
**Arnelify® Server for Python** - is a minimalistic dynamic library which is a powerful server written in C and C++.
@@ -73,7 +73,7 @@ This software is licensed under the <a href="https://github.com/arnelify/arnelif
7373
Join us to help improve this software, fix bugs or implement new functionality. Active participation will help keep the software up-to-date, reliable, and aligned with the needs of its users.
7474

7575
## ⭐ Release Notes
76-
Version 0.7.5 - Minimalistic dynamic library
76+
Version 0.7.7 - Minimalistic dynamic library
7777

7878
We are excited to introduce the Arnelify Server dynamic library for Python! Please note that this version is raw and still in active development.
7979

arnelify_server/index.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,43 +46,42 @@ def __init__(self, opts: dict):
4646
4747
void server_http1_create(opts);
4848
void server_http1_destroy();
49-
void server_http1_set_handler(cHandler cHandler, int hasRemove);
49+
void server_http1_handler(cHandler cHandler);
5050
void server_http1_start(cCallback cCallback);
5151
void server_http1_stop();
5252
""")
5353

54-
def setHandler(self, handler: callable) -> None:
55-
self.handler = handler
54+
def handler(self, cb: callable) -> None:
55+
self.callback = cb
5656

57-
def start(self, callback: callable) -> None:
57+
def start(self, cb: callable) -> None:
5858
cOpts = self.ffi.new("char[]", self.opts.encode('utf-8'))
5959
self.lib.server_http1_create(cOpts)
6060

61-
if hasattr(self, 'handler'):
61+
if hasattr(self, 'callback'):
6262
def handlerWrapper(cSerialized):
6363
serialized: str = self.ffi.string(cSerialized).decode('utf-8')
64-
6564
try:
6665
json.loads(serialized)
6766
except json.JSONDecodeError as err:
6867
print("[Arnelify Server FFI]: Python error: The Request must be a valid JSON.")
6968
exit(1)
69+
7070
req: dict = json.loads(serialized)
7171
res: Http1Res = Http1Res()
72-
73-
self.handler(req, res)
72+
self.callback(req, res)
7473
serialized: str = res.serialize()
7574
return self.ffi.new("char[]", serialized.encode('utf-8'))
7675

7776
self.cHandler = self.ffi.callback("const char* (const char*)", handlerWrapper)
78-
self.lib.server_http1_set_handler(self.cHandler, 0)
77+
self.lib.server_http1_handler(self.cHandler)
7978

8079
def callbackWrapper(cMessage, isError):
8180
message: str = self.ffi.string(cMessage).decode('utf-8')
8281
if isError:
83-
callback(message, True)
82+
cb(message, True)
8483
return
85-
callback(message, False)
84+
cb(message, False)
8685

8786
cCallback = self.ffi.callback("const void (const char*, const int)", callbackWrapper)
8887
def server_thread():

arnelify_server/src/addon.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ Napi::Value server_http1_create(const Napi::CallbackInfo& args) {
195195
json["SERVER_UPLOAD_DIR"].asString());
196196

197197
http1 = new Http1(opts);
198-
http1->setHandler([](const Http1Req& req, Http1Res res) {
198+
http1->handler([](const Http1Req& req, Http1Res res) {
199199
std::promise<const std::string> promise;
200200
std::future<const std::string> future = promise.get_future();
201201
std::thread thread(

arnelify_server/src/ffi.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -158,22 +158,16 @@ void server_http1_create(const char *cOpts) {
158158

159159
void server_http1_destroy() { http1 = nullptr; }
160160

161-
void server_http1_set_handler(const char *(*cHandler)(const char *),
162-
const int hasRemove) {
163-
http1->setHandler([cHandler, hasRemove](const Http1Req &req,
161+
void server_http1_handler(const char *(*cHandler)(const char *)) {
162+
http1->handler([cHandler](const Http1Req &req,
164163
Http1Res res) -> void {
165164
Json::StreamWriterBuilder writer;
166165
writer["indentation"] = "";
167166
writer["emitUTF8"] = true;
168167

169168
const std::string request = Json::writeString(writer, req);
170169
const char *cReq = request.c_str();
171-
const char *cRes = cHandler(cReq);
172-
if (cRes == nullptr) {
173-
std::cout << "[ArnelifyServer FFI]: C error: cRes must be a valid JSON."
174-
<< std::endl;
175-
exit(1);
176-
}
170+
std::string cRes = cHandler(cReq);
177171

178172
Json::Value json;
179173
Json::CharReaderBuilder reader;
@@ -185,7 +179,7 @@ void server_http1_set_handler(const char *(*cHandler)(const char *),
185179
exit(1);
186180
}
187181

188-
if (hasRemove == 1) delete[] cRes;
182+
cRes.clear();
189183
const bool hasCode = json.isMember("code");
190184
if (hasCode) {
191185
res->setCode(json["code"].asInt());

arnelify_server/src/tcp1/http1/index.h

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ class Http1 {
2323
bool isRunning;
2424
int serverSocket;
2525

26-
Http1IO *io;
26+
Http1IO *asyncRead;
27+
Http1IO *asyncHandler;
28+
Http1IO *asyncWrite;
29+
2730
const Http1Opts opts;
2831

29-
Http1Handler handler = [](const Http1Req &req, Http1Res res) -> void {
32+
Http1Handler cb = [](const Http1Req &req, Http1Res res) -> void {
3033
Json::StreamWriterBuilder writer;
3134
writer["indentation"] = "";
3235
writer["emitUTF8"] = true;
@@ -52,16 +55,19 @@ class Http1 {
5255
Http1(Http1Opts &o) : isRunning(false), opts(o), serverSocket(0) {
5356
const int threadLimit =
5457
this->opts.HTTP1_THREAD_LIMIT > 0 ? this->opts.HTTP1_THREAD_LIMIT : 1;
55-
this->io = new Http1IO(threadLimit);
58+
this->asyncRead = new Http1IO(threadLimit);
59+
this->asyncHandler = new Http1IO(threadLimit);
60+
this->asyncWrite = new Http1IO(threadLimit);
5661
}
5762

5863
~Http1() {
5964
this->stop();
60-
this->io->stop();
61-
if (this->io != nullptr) delete this->io;
65+
if (this->asyncRead) delete this->asyncRead;
66+
if (this->asyncHandler) delete this->asyncHandler;
67+
if (this->asyncWrite) delete this->asyncWrite;
6268
}
6369

64-
void setHandler(const Http1Handler &handler) { this->handler = handler; }
70+
void handler(const Http1Handler &cb) { this->cb = cb; }
6571

6672
void start(const Http1Logger &logger) {
6773
this->isRunning = true;
@@ -113,28 +119,27 @@ class Http1 {
113119
exit(1);
114120
}
115121

116-
this->io->onRead([this](Http1Task *task) {
117-
ssize_t bytesRead = 0;
118-
const std::size_t BLOCK_SIZE = this->opts.HTTP1_BLOCK_SIZE_KB * 1024;
119-
char *block = new char[BLOCK_SIZE];
120-
int SIGNAL_ON_BLOCK = 0;
121-
while ((bytesRead = recv(task->clientSocket, block, BLOCK_SIZE, 0)) > 0) {
122-
if (bytesRead == EWOULDBLOCK) {
123-
delete[] block;
122+
this->asyncRead->handler([this](Http1Task *task) {
123+
const std::size_t blockLen = this->opts.HTTP1_BLOCK_SIZE_KB * 1024;
124+
char *block = new char[blockLen];
125+
int ON_RECEIVER = 0;
124126

125-
this->io->addRead(task);
127+
while (!ON_RECEIVER) {
128+
const ssize_t bytesRead = recv(task->clientSocket, block, blockLen, 0);
129+
if (bytesRead == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
130+
delete[] block;
131+
this->asyncRead->addTask(task);
126132
return;
127133
}
128134

129-
SIGNAL_ON_BLOCK = task->receiver->onBlock(block, bytesRead);
130-
if (SIGNAL_ON_BLOCK > 0) break;
135+
ON_RECEIVER = task->receiver->onBlock(block, bytesRead);
131136
}
132137

133138
delete[] block;
134139

135-
const bool isFinish = SIGNAL_ON_BLOCK == 2;
140+
const bool isFinish = ON_RECEIVER == 2;
136141
if (isFinish) {
137-
this->io->addHandler(task);
142+
this->asyncHandler->addTask(task);
138143
return;
139144
}
140145

@@ -151,21 +156,21 @@ class Http1 {
151156
task->transmitter->addBody(body);
152157
task->transmitter->end();
153158

154-
this->io->addWrite(task);
159+
this->asyncWrite->addTask(task);
155160
});
156161

157-
this->io->onHandler([this](Http1Task *task) {
162+
this->asyncHandler->handler([this](Http1Task *task) {
158163
task->transmitter->setLogger(this->logger);
159164
const std::string encoding = task->receiver->getEncoding();
160165
task->transmitter->setEncoding(encoding);
161166
const Http1Req req = task->receiver->finish();
162167
delete task->receiver;
163168

164-
this->handler(req, task->transmitter);
165-
this->io->addWrite(task);
169+
this->cb(req, task->transmitter);
170+
this->asyncWrite->addTask(task);
166171
});
167172

168-
this->io->onWrite([](Http1Task *task) {
173+
this->asyncWrite->handler([this](Http1Task *task) {
169174
task->transmitter->onWrite(
170175
[task](const char *block, const int bytesRead) {
171176
send(task->clientSocket, block, bytesRead, 0);
@@ -175,9 +180,6 @@ class Http1 {
175180
delete task;
176181
});
177182

178-
const std::string port = std::to_string(this->opts.HTTP1_PORT);
179-
this->logger("Server is running on port " + port, false);
180-
181183
sockaddr_in clientAddr;
182184
socklen_t clientLen = sizeof(clientAddr);
183185
const Http1TaskOpts opts(
@@ -187,6 +189,12 @@ class Http1 {
187189
this->opts.HTTP1_MAX_FIELDS_SIZE_TOTAL_MB, this->opts.HTTP1_MAX_FILES,
188190
this->opts.HTTP1_MAX_FILES_SIZE_TOTAL_MB,
189191
this->opts.HTTP1_MAX_FILE_SIZE_MB, this->opts.HTTP1_UPLOAD_DIR);
192+
const std::string port = std::to_string(this->opts.HTTP1_PORT);
193+
this->logger("Server is running on port " + port, false);
194+
195+
this->asyncRead->start();
196+
this->asyncHandler->start();
197+
this->asyncWrite->start();
190198

191199
while (true) {
192200
const bool isStop = !this->isRunning;
@@ -206,15 +214,20 @@ class Http1 {
206214
continue;
207215
}
208216

217+
// int clientFlags = fcntl(clientSocket, F_GETFL, 0);
218+
// if (clientFlags == -1 ||
219+
// fcntl(clientSocket, F_SETFL, clientFlags | O_NONBLOCK) == -1) {
220+
// this->logger("Failed to set client socket non-blocking", true);
221+
// close(clientSocket);
222+
// continue;
223+
// }
224+
209225
Http1Task *task = new Http1Task(clientSocket, opts);
210-
this->io->addRead(task);
226+
this->asyncRead->addTask(task);
211227
}
212228
}
213229

214-
void stop() {
215-
this->io->stop();
216-
this->isRunning = false;
217-
}
230+
void stop() { this->isRunning = false; }
218231
};
219232

220233
#endif

0 commit comments

Comments
 (0)