diff options
author | Richard Knight <q@1bpm.net> | 2024-04-09 22:58:44 +0100 |
---|---|---|
committer | Richard Knight <q@1bpm.net> | 2024-04-09 22:58:44 +0100 |
commit | d4701791a2d04ff52bea456ebb34f4d79819f97e (patch) | |
tree | c582c6b10b271c550c9618cb0d818c5b27a98620 /src | |
download | csound-curl-master.tar.gz csound-curl-master.tar.bz2 csound-curl-master.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/opcodes.cpp | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/src/opcodes.cpp b/src/opcodes.cpp new file mode 100644 index 0000000..5f27f60 --- /dev/null +++ b/src/opcodes.cpp @@ -0,0 +1,355 @@ +#include <plugin.h> +#include "handling.h" +#include <curl/curl.h> +#include <atomic> + +const char* ciniterror = "cannot initialise CURL"; + +static size_t write_callback(void* contents, size_t size, size_t nmemb, void *userp) { + ((std::string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; +} + +class HTTPRequest { +private: + csnd::Csound* csound; + CURL* curl; + char* url; + + void curl_reset() { + curl_easy_reset(curl); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + +public: + CURLcode curlResult; + char* curlError; + long httpResponseCode; + std::string response; + + HTTPRequest(csnd::Csound* csound, char* url) : + csound(csound), + url(url) + { + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if (!curl) { + curl_global_cleanup(); + throw std::runtime_error((char*) ciniterror); + } + + + } + + ~HTTPRequest() { + curl_easy_cleanup(curl); + curl_global_cleanup(); + } + + void post(char* postdata) { + curl_reset(); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata); + curlResult = curl_easy_perform(curl); + if (curlResult != CURLE_OK) { + curlError = (char*) curl_easy_strerror(curlResult); + } + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpResponseCode); + } + + void get() { + curl_reset(); + curlResult = curl_easy_perform(curl); + if (curlResult != CURLE_OK) { + curlError = (char*) curl_easy_strerror(curlResult); + } + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpResponseCode); + } + + +}; + + +class RequestThread : public csnd::Thread { + std::atomic_bool spinlock; + std::atomic_bool on; + int sleepTime; +public: + HTTPRequest* req; + char* postdata; + bool dopost; + char* error; + bool errored; + bool done; + bool pending; + RequestThread(csnd::Csound* csound, char* url, bool dopost, char* postdata=NULL) : + Thread(csound), + done(false), + pending(false), + on(true), + spinlock(false), + postdata(postdata), + dopost(dopost), + sleepTime(10) + { + try { + req = new HTTPRequest(csound, url); + } catch (const std::exception &e) { + errored = true; + error = csound->strdup(req->curlError); + } + }; + + uintptr_t run() { + while (on) { + lock(); + if (pending) { + try { + if (dopost) { + req->post(postdata); + } else { + req->get(); + } + + if (req->curlResult != CURLE_OK) { + errored = true; + error = csound->strdup(req->curlError); + } + + done = true; + pending = false; + } catch (const std::exception &e) { + errored = true; + done = true; + pending = false; + error = csound->strdup((char*) e.what()); + } + } + unlock(); + csound->sleep(sleepTime); + } + return 0; + } + + void lock() { + while (spinlock == true) { + csound->sleep(sleepTime); + } + spinlock = true; + } + + void unlock() { + spinlock = false; + } + + void stop() { + on = false; + } +}; + + +struct curlpostk : csnd::Plugin<3, 2> { + static constexpr char const *otypes = "kkS"; + static constexpr char const *itypes = "SS"; + RequestThread request; + + int init() { + csound->plugin_deinit(this); + STRINGDAT &url = inargs.str_data(0); + STRINGDAT &postdata = inargs.str_data(1); + csnd::constr(&request, csound, url.data, true, postdata.data); + return OK; + } + + int deinit() { + request.stop(); + request.join(); + csnd::destr(&request); + return OK; + } + + int kperf() { + outargs[0] = FL(0); + if (request.done) { + if (request.errored) { + return csound->perf_error(request.error, this); + } + outargs[0] = FL(1); + } else if (!request.pending) { + request.lock(); + request.pending = true; + request.unlock(); + } + outargs[1] = (MYFLT) request.req->httpResponseCode; + STRINGDAT &resultstring = outargs.str_data(2); + resultstring.data = csound->strdup((char*) request.req->response.c_str()); + resultstring.size = request.req->response.size(); + return OK; + } +}; + + +struct curlgetk : csnd::Plugin<3, 1> { + static constexpr char const *otypes = "kkS"; + static constexpr char const *itypes = "S"; + RequestThread request; + + int init() { + csound->plugin_deinit(this); + STRINGDAT &url = inargs.str_data(0); + csnd::constr(&request, csound, url.data, false); + return OK; + } + + int deinit() { + request.stop(); + request.join(); + csnd::destr(&request); + return OK; + } + + int kperf() { + outargs[0] = FL(0); + if (request.done) { + if (request.errored) { + return csound->perf_error(request.error, this); + } + outargs[0] = FL(1); + } else if (!request.pending) { + request.lock(); + request.pending = true; + request.unlock(); + } + outargs[1] = (MYFLT) request.req->httpResponseCode; + STRINGDAT &resultstring = outargs.str_data(2); + resultstring.data = csound->strdup((char*) request.req->response.c_str()); + resultstring.size = request.req->response.size(); + return OK; + } +}; + + + +struct curlpost : csnd::Plugin<2, 2> { + static constexpr char const *otypes = "iS"; + static constexpr char const *itypes = "SS"; + + int init() { + STRINGDAT &url = inargs.str_data(0); + STRINGDAT &postdata = inargs.str_data(1); + + HTTPRequest* req; + try { + req = new HTTPRequest(csound, url.data); + } catch (const std::exception &e) { + csound->init_error(csound->strdup((char*) e.what())); + } + + req->post(postdata.data); + + if (req->curlResult != CURLE_OK) { + return csound->init_error(csound->strdup(req->curlError)); + } + + outargs[0] = (MYFLT) req->httpResponseCode; + STRINGDAT &resultstring = outargs.str_data(1); + resultstring.data = csound->strdup((char*) req->response.c_str()); + resultstring.size = req->response.size(); + + return OK; + } + +}; + + +struct curlget : csnd::Plugin<2, 1> { + static constexpr char const *otypes = "iS"; + static constexpr char const *itypes = "S"; + + int init() { + STRINGDAT &url = inargs.str_data(0); + + HTTPRequest* req; + try { + req = new HTTPRequest(csound, url.data); + } catch (const std::exception &e) { + csound->init_error(csound->strdup((char*) e.what())); + } + + req->get(); + + if (req->curlResult != CURLE_OK) { + return csound->init_error(csound->strdup(req->curlError)); + } + + outargs[0] = (MYFLT) req->httpResponseCode; + STRINGDAT &resultstring = outargs.str_data(1); + resultstring.data = csound->strdup((char*) req->response.c_str()); + resultstring.size = req->response.size(); + + return OK; + } + +}; + + +struct curlurlencode : csnd::Plugin<1, 1> { + static constexpr char const *otypes = "S"; + static constexpr char const *itypes = "S"; + + int init() { + CURL* curl = curl_easy_init(); + STRINGDAT &input = inargs.str_data(0); + STRINGDAT &output = outargs.str_data(0); + char* encoded = curl_easy_escape(curl, input.data, strlen(input.data)); + output.data = csound->strdup(encoded); + output.size = strlen(output.data); + curl_free(encoded); + curl_easy_cleanup(curl); + return OK; + } +}; + +struct curlurlencodek : csnd::Plugin<1, 2> { + static constexpr char const *otypes = "S"; + static constexpr char const *itypes = "Sk"; + CURL* curl; + + int init() { + csound->plugin_deinit(this); + curl = curl_easy_init(); + return OK; + } + + int kperf() { + if (inargs[1] == 1) { + STRINGDAT &input = inargs.str_data(0); + STRINGDAT &output = outargs.str_data(0); + char* encoded = curl_easy_escape(curl, input.data, strlen(input.data)); + output.data = csound->strdup(encoded); + output.size = strlen(output.data); + curl_free(encoded); + } + return OK; + } + + int deinit() { + curl_easy_cleanup(curl); + return OK; + } +}; + + +#include <modload.h> +void csnd::on_load(csnd::Csound *csound) { + csnd::plugin<curlpost>(csound, "curlpost", csnd::thread::i); + csnd::plugin<curlget>(csound, "curlget", csnd::thread::i); + csnd::plugin<curlpostk>(csound, "curlpostk", csnd::thread::ik); + csnd::plugin<curlgetk>(csound, "curlgetk", csnd::thread::ik); + csnd::plugin<curlurlencode>(csound, "curlurlencode", csnd::thread::i); + csnd::plugin<curlurlencodek>(csound, "curlurlencodek", csnd::thread::ik); +} |