1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 23:37:36 +00:00

Start working on a Downloader app and backing classes in LibGUI.

LibGUI is slowly becoming LibKitchensink but I'm okay with this for now.
This commit is contained in:
Andreas Kling 2019-04-07 14:36:10 +02:00
parent c7365a00f8
commit 8f30657390
21 changed files with 375 additions and 1 deletions

View file

@ -5,6 +5,7 @@
#include <AK/AKString.h>
#include <AK/Types.h>
#include <AK/WeakPtr.h>
#include <AK/Function.h>
#include <Kernel/KeyCode.h>
#include <LibGUI/GWindowType.h>
@ -28,6 +29,7 @@ public:
KeyUp,
Timer,
DeferredDestroy,
DeferredInvoke,
WindowEntered,
WindowLeft,
WindowBecameInactive,
@ -55,6 +57,19 @@ private:
Type m_type { Invalid };
};
class GDeferredInvocationEvent : public GEvent {
friend class GEventLoop;
public:
GDeferredInvocationEvent(Function<void(GObject&)> invokee)
: GEvent(GEvent::Type::DeferredInvoke)
, m_invokee(move(invokee))
{
}
private:
Function<void(GObject&)> m_invokee;
};
class GWMEvent : public GEvent {
public:
GWMEvent(Type type, int client_id, int window_id)

View file

@ -158,6 +158,9 @@ int GEventLoop::exec()
default:
dbgprintf("Event type %u with no receiver :(\n", event.type());
}
} else if (event.type() == GEvent::Type::DeferredInvoke) {
printf("DeferredInvoke: receiver=%s{%p}\n", receiver->class_name(), receiver);
static_cast<GDeferredInvocationEvent&>(event).m_invokee(*receiver);
} else {
receiver->event(event);
}

View file

@ -0,0 +1,47 @@
#include <LibGUI/GHttpNetworkJob.h>
#include <LibGUI/GHttpResponse.h>
#include <LibGUI/GTCPSocket.h>
#include <stdio.h>
GHttpNetworkJob::GHttpNetworkJob(const GHttpRequest& request)
: m_request(request)
{
}
GHttpNetworkJob::~GHttpNetworkJob()
{
}
void GHttpNetworkJob::start()
{
ASSERT(!m_socket);
m_socket = new GTCPSocket(this);
int success = m_socket->connect(m_request.hostname(), m_request.port());
if (!success)
return did_fail(GNetworkJob::Error::ConnectionFailed);
auto raw_request = m_request.to_raw_request();
printf("raw_request:\n%s\n", raw_request.pointer());
success = m_socket->send(raw_request);
if (!success)
return did_fail(GNetworkJob::Error::TransmissionFailed);
Vector<byte> buffer;
while (m_socket->is_connected()) {
auto payload = m_socket->receive(100000);
if (!payload) {
if (m_socket->eof())
break;
return did_fail(GNetworkJob::Error::TransmissionFailed);
}
buffer.append(payload.pointer(), payload.size());
}
auto response = GHttpResponse::create(1, ByteBuffer::copy(buffer.data(), buffer.size()));
deferred_invoke([this, response] (GObject&) {
printf("in the deferred invoke lambda\n");
did_finish(move(response));
});
}

20
LibGUI/GHttpNetworkJob.h Normal file
View file

@ -0,0 +1,20 @@
#pragma once
#include <LibGUI/GNetworkJob.h>
#include <LibGUI/GHttpRequest.h>
class GTCPSocket;
class GHttpNetworkJob final : public GNetworkJob {
public:
explicit GHttpNetworkJob(const GHttpRequest&);
virtual ~GHttpNetworkJob() override;
virtual void start() override;
virtual const char* class_name() const override { return "GHttpNetworkJob"; }
private:
GHttpRequest m_request;
GTCPSocket* m_socket { nullptr };
};

45
LibGUI/GHttpRequest.cpp Normal file
View file

@ -0,0 +1,45 @@
#include <LibGUI/GHttpRequest.h>
#include <LibGUI/GHttpNetworkJob.h>
#include <LibGUI/GEventLoop.h>
#include <AK/StringBuilder.h>
GHttpRequest::GHttpRequest()
{
}
GHttpRequest::~GHttpRequest()
{
}
GNetworkJob* GHttpRequest::schedule()
{
auto* job = new GHttpNetworkJob(*this);
job->start();
return job;
}
String GHttpRequest::method_name() const
{
switch (m_method) {
case Method::GET:
return "GET";
case Method::HEAD:
return "HEAD";
case Method::POST:
return "POST";
default:
ASSERT_NOT_REACHED();
}
}
ByteBuffer GHttpRequest::to_raw_request() const
{
StringBuilder builder;
builder.append(method_name());
builder.append(' ');
builder.append(m_path);
builder.append(" HTTP/1.0\nHost: ");
builder.append(m_hostname);
builder.append("\n\n");
return builder.to_byte_buffer();
}

34
LibGUI/GHttpRequest.h Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include <AK/AKString.h>
class GNetworkJob;
class GHttpRequest {
public:
enum Method { Invalid, HEAD, GET, POST };
GHttpRequest();
~GHttpRequest();
String hostname() const { return m_hostname; }
int port() const { return m_port; }
String path() const { return m_path; }
Method method() const { return m_method; }
void set_hostname(const String& hostname) { m_hostname = hostname; }
void set_port(int port) { m_port = port; }
void set_path(const String& path) { m_path = path; }
void set_method(Method method) { m_method = method; }
String method_name() const;
ByteBuffer to_raw_request() const;
GNetworkJob* schedule();
private:
String m_hostname;
String m_path;
int m_port { 80 };
Method m_method { GET };
};

11
LibGUI/GHttpResponse.cpp Normal file
View file

@ -0,0 +1,11 @@
#include <LibGUI/GHttpResponse.h>
GHttpResponse::GHttpResponse(int code, ByteBuffer&& payload)
: GNetworkResponse(move(payload))
, m_code(code)
{
}
GHttpResponse::~GHttpResponse()
{
}

23
LibGUI/GHttpResponse.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include <LibGUI/GNetworkResponse.h>
#include <AK/AKString.h>
#include <AK/HashMap.h>
class GHttpResponse : public GNetworkResponse {
public:
virtual ~GHttpResponse() override;
static Retained<GHttpResponse> create(int code, ByteBuffer&& payload)
{
return adopt(*new GHttpResponse(code, move(payload)));
}
int code() const { return m_code; }
const HashMap<String, String>& headers() const { return m_headers; }
private:
GHttpResponse(int code, ByteBuffer&&);
int m_code { 0 };
HashMap<String, String> m_headers;
};

View file

@ -42,6 +42,10 @@ ByteBuffer GIODevice::read(int max_size)
set_error(errno);
return { };
}
if (nread == 0) {
set_eof(true);
return { };
}
buffer.trim(nread);
return buffer;
}

27
LibGUI/GNetworkJob.cpp Normal file
View file

@ -0,0 +1,27 @@
#include <LibGUI/GNetworkJob.h>
#include <LibGUI/GNetworkResponse.h>
#include <stdio.h>
GNetworkJob::GNetworkJob()
{
}
GNetworkJob::~GNetworkJob()
{
}
void GNetworkJob::did_finish(Retained<GNetworkResponse>&& response)
{
m_response = move(response);
printf("%s{%p} job did_finish!\n", class_name(), this);
ASSERT(on_finish);
on_finish(true);
}
void GNetworkJob::did_fail(Error error)
{
m_error = error;
dbgprintf("%s{%} job did_fail! error=%u\n", class_name(), this, (unsigned)error);
ASSERT(on_finish);
on_finish(false);
}

36
LibGUI/GNetworkJob.h Normal file
View file

@ -0,0 +1,36 @@
#pragma once
#include <LibGUI/GObject.h>
#include <AK/Function.h>
class GNetworkResponse;
class GNetworkJob : public GObject {
public:
enum class Error {
None,
ConnectionFailed,
TransmissionFailed,
};
virtual ~GNetworkJob() override;
Function<void(bool success)> on_finish;
bool has_error() const { return m_error != Error::None; }
Error error() const { return m_error; }
GNetworkResponse* response() { return m_response.ptr(); }
const GNetworkResponse* response() const { return m_response.ptr(); }
virtual void start() = 0;
virtual const char* class_name() const override { return "GNetworkJob"; }
protected:
GNetworkJob();
void did_finish(Retained<GNetworkResponse>&&);
void did_fail(Error);
private:
RetainPtr<GNetworkResponse> m_response;
Error m_error { Error::None };
};

View file

@ -0,0 +1,10 @@
#include <LibGUI/GNetworkResponse.h>
GNetworkResponse::GNetworkResponse(ByteBuffer&& payload)
: m_payload(payload)
{
}
GNetworkResponse::~GNetworkResponse()
{
}

18
LibGUI/GNetworkResponse.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#include <AK/Retainable.h>
#include <AK/ByteBuffer.h>
class GNetworkResponse : public Retainable<GNetworkResponse> {
public:
virtual ~GNetworkResponse();
bool is_error() const { return m_error; }
const ByteBuffer& payload() const { return m_payload; }
protected:
explicit GNetworkResponse(ByteBuffer&&);
bool m_error { false };
ByteBuffer m_payload;
};

View file

@ -99,5 +99,9 @@ void GObject::dump_tree(int indent)
for (auto* child : children()) {
child->dump_tree(indent + 2);
}
}
void GObject::deferred_invoke(Function<void(GObject&)> invokee)
{
GEventLoop::current().post_event(*this, make<GDeferredInvocationEvent>(move(invokee)));
}

View file

@ -1,5 +1,6 @@
#pragma once
#include <AK/Function.h>
#include <AK/Vector.h>
#include <AK/Weakable.h>
@ -32,6 +33,8 @@ public:
void dump_tree(int indent = 0);
void deferred_invoke(Function<void(GObject&)>);
virtual bool is_widget() const { return false; }
virtual bool is_window() const { return false; }

View file

@ -58,6 +58,11 @@ LIBGUI_OBJS = \
GFileSystemModel.o \
GSplitter.o \
GTimer.o \
GNetworkJob.o \
GNetworkResponse.o \
GHttpRequest.o \
GHttpResponse.o \
GHttpNetworkJob.o \
GWindow.o
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)