pocketpy/src/requests.h
blueloveTH fcc13cb422 ...
2023-04-30 22:29:04 +08:00

103 lines
3.0 KiB
C++

#pragma once
#include "common.h"
#include "obj.h"
#include "vm.h"
#include "_generated.h"
#if __has_include("httplib.h")
#include "httplib.h"
namespace pkpy {
inline void add_module_requests(VM* vm){
static StrName m_requests("requests");
static StrName m_Response("Response");
PyObject* mod = vm->new_module(m_requests);
CodeObject_ code = vm->compile(kPythonLibs["requests"], "requests.py", EXEC_MODE);
vm->_exec(code, mod);
vm->bind_func<4>(mod, "_request", [](VM* vm, ArgsView args){
Str method = CAST(Str&, args[0]);
Str url = CAST(Str&, args[1]);
PyObject* headers = args[2]; // a dict object
PyObject* body = args[3]; // a bytes object
if(url.index("http://") != 0){
vm->ValueError("url must start with http://");
}
for(char c: url){
switch(c){
case '.':
case '-':
case '_':
case '~':
case ':':
case '/':
break;
default:
if(!isalnum(c)){
vm->ValueError(fmt("invalid character in url: '", c, "'"));
}
}
}
int slash = url.index("/", 7);
Str path = "/";
if(slash != -1){
path = url.substr(slash);
url = url.substr(0, slash);
if(path.empty()) path = "/";
}
httplib::Client client(url.str());
httplib::Headers h;
if(headers != vm->None){
List list = CAST(List&, headers);
for(auto& item : list){
Tuple t = CAST(Tuple&, item);
Str key = CAST(Str&, t[0]);
Str value = CAST(Str&, t[1]);
h.emplace(key.str(), value.str());
}
}
auto _to_resp = [=](const httplib::Result& res){
return vm->call(
vm->_modules[m_requests]->attr(m_Response),
VAR(res->status),
VAR(res->reason),
VAR(Bytes(res->body))
);
};
if(method == "GET"){
httplib::Result res = client.Get(path.str(), h);
return _to_resp(res);
}else if(method == "POST"){
Bytes b = CAST(Bytes&, body);
httplib::Result res = client.Post(path.str(), h, b.data(), b.size(), "application/octet-stream");
return _to_resp(res);
}else if(method == "PUT"){
Bytes b = CAST(Bytes&, body);
httplib::Result res = client.Put(path.str(), h, b.data(), b.size(), "application/octet-stream");
return _to_resp(res);
}else if(method == "DELETE"){
httplib::Result res = client.Delete(path.str(), h);
return _to_resp(res);
}else{
vm->ValueError("invalid method");
}
UNREACHABLE();
});
}
} // namespace pkpy
#else
inline void add_module_requests(void* vm){ }
#endif