changing error to something with more generic codes
This commit is contained in:
parent
ec9db2863b
commit
db5b1b8aa0
|
@ -32,11 +32,11 @@ UnixIoStream::UnixIoStream(UnixEventPort &event_port, int file_descriptor,
|
|||
}
|
||||
|
||||
ErrorOr<size_t> UnixIoStream::read(void *buffer, size_t length) {
|
||||
ssize_t read_bytes = unixRead(fd(), buffer, length);
|
||||
if( read_bytes > 0 ){
|
||||
ssize_t read_bytes = unixRead(fd(), buffer, length);
|
||||
if (read_bytes > 0) {
|
||||
return static_cast<size_t>(read_bytes);
|
||||
}else if(read_bytes == 0){
|
||||
return criticalError("Disconnected", static_cast<int8_t>(Error::Type::Disconnected));
|
||||
} else if (read_bytes == 0) {
|
||||
return criticalError("Disconnected", Error::Code::Disconnected);
|
||||
}
|
||||
|
||||
return recoverableError("Currently busy");
|
||||
|
@ -56,17 +56,17 @@ Conveyor<void> UnixIoStream::onReadDisconnected() {
|
|||
|
||||
ErrorOr<size_t> UnixIoStream::write(const void *buffer, size_t length) {
|
||||
ssize_t write_bytes = unixWrite(fd(), buffer, length);
|
||||
if( write_bytes > 0){
|
||||
if (write_bytes > 0) {
|
||||
return static_cast<size_t>(write_bytes);
|
||||
}
|
||||
|
||||
int error = errno;
|
||||
|
||||
if( error == EAGAIN || error == EWOULDBLOCK ){
|
||||
if (error == EAGAIN || error == EWOULDBLOCK) {
|
||||
return recoverableError("Currently busy");
|
||||
}
|
||||
|
||||
return criticalError("Disconnected", static_cast<int8_t>(Error::Type::Disconnected));
|
||||
return criticalError("Disconnected", Error::Code::Disconnected);
|
||||
}
|
||||
|
||||
Conveyor<void> UnixIoStream::writeReady() {
|
||||
|
|
|
@ -15,7 +15,9 @@ namespace gin {
|
|||
classname(const classname &) = delete; \
|
||||
classname &operator=(const classname &) = delete
|
||||
|
||||
#define GIN_ASSERT(expression) assert(expression) if (!expression)
|
||||
#define GIN_ASSERT(expression) \
|
||||
assert(expression); \
|
||||
if (!expression)
|
||||
|
||||
template <typename T> using Maybe = std::optional<T>;
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include "error.h"
|
||||
|
||||
namespace gin {
|
||||
Error::Error() : error_{static_cast<Error::Type>(0)} {}
|
||||
Error::Error() : error_{static_cast<Error::Code>(0)} {}
|
||||
|
||||
Error::Error(const std::string_view &msg, int8_t code)
|
||||
: error_message{msg}, error_{static_cast<Error::Type>(code)} {}
|
||||
Error::Error(const std::string_view &msg, Error::Code code)
|
||||
: error_message{msg}, error_{static_cast<Error::Code>(code)} {}
|
||||
|
||||
Error::Error(std::string &&msg, int8_t code)
|
||||
: error_message{std::move(msg)}, error_{static_cast<Error::Type>(code)} {}
|
||||
Error::Error(std::string &&msg, Error::Code code)
|
||||
: error_message{std::move(msg)}, error_{static_cast<Error::Code>(code)} {}
|
||||
|
||||
Error::Error(Error &&error)
|
||||
: error_message{std::move(error.error_message)}, error_{std::move(
|
||||
|
@ -30,11 +30,17 @@ const std::string_view Error::message() const {
|
|||
error_message);
|
||||
}
|
||||
|
||||
bool Error::failed() const { return static_cast<int8_t>(error_) != 0; }
|
||||
bool Error::failed() const {
|
||||
return static_cast<std::underlying_type_t<Error::Code>>(error_) != 0;
|
||||
}
|
||||
|
||||
bool Error::isCritical() const { return static_cast<int8_t>(error_) < 0; }
|
||||
bool Error::isCritical() const {
|
||||
return static_cast<std::underlying_type_t<Error::Code>>(error_) < 0;
|
||||
}
|
||||
|
||||
bool Error::isRecoverable() const { return static_cast<int8_t>(error_) > 0; }
|
||||
bool Error::isRecoverable() const {
|
||||
return static_cast<std::underlying_type_t<Error::Code>>(error_) > 0;
|
||||
}
|
||||
|
||||
Error Error::copyError() const {
|
||||
Error error;
|
||||
|
@ -48,16 +54,14 @@ Error Error::copyError() const {
|
|||
return error;
|
||||
}
|
||||
|
||||
Error::Type Error::code() const {
|
||||
return static_cast
|
||||
Error::Code Error::code() const { return static_cast<Error::Code>(error_); }
|
||||
|
||||
Error criticalError(const std::string_view &generic, Error::Code c) {
|
||||
return Error{generic, c};
|
||||
}
|
||||
|
||||
Error criticalError(const std::string_view &generic) {
|
||||
return Error{generic, -1};
|
||||
}
|
||||
|
||||
Error recoverableError(const std::string_view &generic) {
|
||||
return Error{generic, 1};
|
||||
Error recoverableError(const std::string_view &generic, Error::Code c) {
|
||||
return Error{generic, c};
|
||||
}
|
||||
|
||||
Error noError() { return Error{}; }
|
||||
|
|
|
@ -14,17 +14,21 @@ namespace gin {
|
|||
*/
|
||||
class Error {
|
||||
public:
|
||||
enum class Type : int8_t {
|
||||
Disconnected = -99
|
||||
enum class Code : int16_t {
|
||||
GenericCritical = -1,
|
||||
GenericRecoverable = 1,
|
||||
Disconnected = -99,
|
||||
Exhausted = 99
|
||||
};
|
||||
|
||||
private:
|
||||
std::variant<std::string_view, std::string> error_message;
|
||||
Type error_;
|
||||
Code error_;
|
||||
|
||||
public:
|
||||
Error();
|
||||
Error(const std::string_view &msg, int8_t code);
|
||||
Error(std::string &&msg, int8_t code);
|
||||
Error(const std::string_view &msg, Error::Code code);
|
||||
Error(std::string &&msg, Error::Code code);
|
||||
Error(Error &&error);
|
||||
|
||||
GIN_FORBID_COPY(Error);
|
||||
|
@ -39,11 +43,11 @@ public:
|
|||
|
||||
Error copyError() const;
|
||||
|
||||
Type code() const;
|
||||
Code code() const;
|
||||
};
|
||||
|
||||
template <typename Formatter>
|
||||
Error makeError(const Formatter &formatter, int8_t code,
|
||||
Error makeError(const Formatter &formatter, Error::Code code,
|
||||
const std::string_view &generic) {
|
||||
try {
|
||||
std::string error_msg = formatter();
|
||||
|
@ -53,20 +57,23 @@ Error makeError(const Formatter &formatter, int8_t code,
|
|||
}
|
||||
}
|
||||
|
||||
Error criticalError(const std::string_view &generic);
|
||||
Error criticalError(const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericCritical);
|
||||
|
||||
template <typename Formatter>
|
||||
Error criticalError(const Formatter &formatter,
|
||||
const std::string_view &generic) {
|
||||
return makeError(formatter, -1, generic);
|
||||
Error criticalError(const Formatter &formatter, const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericCritical) {
|
||||
return makeError(formatter, c, generic);
|
||||
}
|
||||
|
||||
Error recoverableError(const std::string_view &generic);
|
||||
Error recoverableError(const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericRecoverable);
|
||||
|
||||
template <typename Formatter>
|
||||
Error recoverableError(const Formatter &formatter,
|
||||
const std::string_view &generic) {
|
||||
return makeError(formatter, -1, generic);
|
||||
const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericRecoverable) {
|
||||
return makeError(formatter, c, generic);
|
||||
}
|
||||
|
||||
Error noError();
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
#include "io.h"
|
||||
|
||||
namespace gin {} // namespace gin
|
||||
namespace gin {
|
||||
|
||||
AsyncIoStream::AsyncIoStream(Own<IoStream> str)
|
||||
: stream{std::move(str)},
|
||||
read_ready{stream->readReady().then([this]() {}).sink()},
|
||||
write_ready{stream->writeReady()
|
||||
.then([this]() {
|
||||
|
||||
})
|
||||
.sink()},
|
||||
read_disconnected{stream->onReadDisconnected()
|
||||
.then([this]() {
|
||||
|
||||
})
|
||||
.sink()} {}
|
||||
|
||||
void AsyncIoStream::read(void *buffer, size_t min_length, size_t max_length) {}
|
||||
|
||||
Conveyor<size_t> AsyncIoStream::readDone() {
|
||||
auto caf = newConveyorAndFeeder<size_t>();
|
||||
read_stepper.read_done = std::move(caf.feeder);
|
||||
return std::move(caf.conveyor);
|
||||
}
|
||||
|
||||
void AsyncIoStream::write(const void *buffer, size_t length) {}
|
||||
|
||||
Conveyor<size_t> AsyncIoStream::writeDone() {
|
||||
auto caf = newConveyorAndFeeder<size_t>();
|
||||
write_stepper.write_done = std::move(caf.feeder);
|
||||
return std::move(caf.conveyor);
|
||||
}
|
||||
} // namespace gin
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "async.h"
|
||||
#include "common.h"
|
||||
#include "io_helpers.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -40,12 +41,11 @@ public:
|
|||
virtual ~IoStream() = default;
|
||||
};
|
||||
|
||||
/*
|
||||
class AsyncInputStream {
|
||||
public:
|
||||
virtual ~AsyncInputStream() = default;
|
||||
|
||||
virtual void read(void* buffer, size_t min_length, size_t max_length) = 0;
|
||||
virtual void read(void *buffer, size_t min_length, size_t max_length) = 0;
|
||||
|
||||
virtual Conveyor<size_t> readDone() = 0;
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ class AsyncOutputStream {
|
|||
public:
|
||||
virtual ~AsyncOutputStream() = default;
|
||||
|
||||
virtual void write(const void* buffer, size_t length) = 0;
|
||||
virtual void write(const void *buffer, size_t length) = 0;
|
||||
|
||||
virtual Conveyor<size_t> writeDone() = 0;
|
||||
};
|
||||
|
@ -62,18 +62,25 @@ public:
|
|||
class AsyncIoStream : public AsyncInputStream, public AsyncOutputStream {
|
||||
private:
|
||||
Own<IoStream> stream;
|
||||
|
||||
SinkConveyor read_ready;
|
||||
SinkConveyor write_ready;
|
||||
SinkConveyor read_disconnected;
|
||||
|
||||
ReadTaskAndStepHelper read_stepper;
|
||||
WriteTaskAndStepHelper write_stepper;
|
||||
|
||||
public:
|
||||
AsyncIoStream(Own<IoStream> str);
|
||||
|
||||
void read(void* buffer, size_t min_length, size_t max_length) override;
|
||||
void read(void *buffer, size_t min_length, size_t max_length) override;
|
||||
|
||||
Conveyor<size_t> readDone() override;
|
||||
|
||||
void write(const void* buffer, size_t length) override;
|
||||
void write(const void *buffer, size_t length) override;
|
||||
|
||||
Conveyor<size_t> writeDone() override;
|
||||
};
|
||||
*/
|
||||
|
||||
class Server {
|
||||
public:
|
||||
|
|
|
@ -2,40 +2,43 @@
|
|||
|
||||
#include "io.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace gin {
|
||||
void ReadTaskAndStepHelper::readStep(InputStream &reader) {
|
||||
if (read_task.has_value()) {
|
||||
ReadIoTask &task = *read_task;
|
||||
|
||||
ssize_t n = reader.read(task.buffer, task.max_length);
|
||||
|
||||
if (n <= 0) {
|
||||
if (n == 0) {
|
||||
if (on_read_disconnect) {
|
||||
on_read_disconnect->feed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
int error = errno;
|
||||
if (error == EAGAIN || error == EWOULDBLOCK) {
|
||||
return;
|
||||
} else {
|
||||
ErrorOr<size_t> n_err = reader.read(task.buffer, task.max_length);
|
||||
if (n_err.isError()) {
|
||||
const Error &error = n_err.error();
|
||||
if (error.isCritical()) {
|
||||
if (read_done) {
|
||||
read_done->fail(criticalError("Read failed"));
|
||||
read_done->fail(error.copyError());
|
||||
}
|
||||
read_task = std::nullopt;
|
||||
}
|
||||
} else if (static_cast<size_t>(n) >= task.min_length &&
|
||||
static_cast<size_t>(n) <= task.max_length) {
|
||||
if (read_done) {
|
||||
read_done->feed(static_cast<size_t>(n));
|
||||
} else if (n_err.isValue()) {
|
||||
size_t n = n_err.value();
|
||||
if (static_cast<size_t>(n) >= task.min_length &&
|
||||
static_cast<size_t>(n) <= task.max_length) {
|
||||
if (read_done) {
|
||||
// Accumulated bytes are not pushed
|
||||
read_done->feed(n + task.already_read);
|
||||
}
|
||||
read_task = std::nullopt;
|
||||
} else {
|
||||
task.buffer = reinterpret_cast<void *>(task.buffer) + n;
|
||||
task.min_length -= static_cast<size_t>(n);
|
||||
task.max_length -= static_cast<size_t>(n);
|
||||
task.already_read += n;
|
||||
}
|
||||
size_t max_len = task.max_length;
|
||||
read_task = std::nullopt;
|
||||
|
||||
} else {
|
||||
task.buffer = reinterpret_cast<void *>(task.buffer) + n;
|
||||
task.min_length -= static_cast<size_t>(n);
|
||||
task.max_length -= static_cast<size_t>(n);
|
||||
if (read_done) {
|
||||
read_done->fail(criticalError("Read failed"));
|
||||
}
|
||||
read_task = std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,27 +47,35 @@ void WriteTaskAndStepHelper::writeStep(OutputStream &writer) {
|
|||
if (write_task.has_value()) {
|
||||
WriteIoTask &task = *write_task;
|
||||
|
||||
ssize_t n = writer.write(task.buffer, task.length);
|
||||
ErrorOr<size_t> n_err = writer.write(task.buffer, task.length);
|
||||
|
||||
if (n < 0) {
|
||||
int error = errno;
|
||||
if (error == EAGAIN || error == EWOULDBLOCK) {
|
||||
return;
|
||||
} else {
|
||||
if (n_err.isValue()) {
|
||||
size_t n = n_err.value();
|
||||
assert(n <= task.length);
|
||||
if (n == task.length) {
|
||||
if (write_done) {
|
||||
write_done->fail(criticalError("Write failed"));
|
||||
write_done->feed(n + task.already_written);
|
||||
}
|
||||
write_task = std::nullopt;
|
||||
} else {
|
||||
task.buffer = reinterpret_cast<const void *>(task.buffer) +
|
||||
static_cast<size_t>(n);
|
||||
task.length -= n;
|
||||
task.already_written += n;
|
||||
}
|
||||
} else if (n_err.isError()) {
|
||||
const Error &error = n_err.error();
|
||||
if (error.isCritical()) {
|
||||
if (write_done) {
|
||||
write_done->fail(error.copyError());
|
||||
}
|
||||
write_task = std::nullopt;
|
||||
}
|
||||
} else if (static_cast<size_t>(n) == task.length) {
|
||||
} else {
|
||||
if (write_done) {
|
||||
write_done->feed(static_cast<size_t>(task.length));
|
||||
write_done->fail(criticalError("Write failed"));
|
||||
}
|
||||
write_task = std::nullopt;
|
||||
} else {
|
||||
task.buffer = reinterpret_cast<const void *>(task.buffer) +
|
||||
static_cast<size_t>(n);
|
||||
task.length -= static_cast<size_t>(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <kelgin/async.h>
|
||||
#include <kelgin/common.h>
|
||||
#include "async.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
@ -24,6 +24,7 @@ public:
|
|||
void *buffer;
|
||||
size_t min_length;
|
||||
size_t max_length;
|
||||
size_t already_read = 0;
|
||||
};
|
||||
std::optional<ReadIoTask> read_task;
|
||||
Own<ConveyorFeeder<size_t>> read_done = nullptr;
|
||||
|
@ -41,6 +42,7 @@ public:
|
|||
struct WriteIoTask {
|
||||
const void *buffer;
|
||||
size_t length;
|
||||
size_t already_written = 0;
|
||||
};
|
||||
std::optional<WriteIoTask> write_task;
|
||||
Own<ConveyorFeeder<size_t>> write_done = nullptr;
|
||||
|
|
Loading…
Reference in New Issue