<img src = "http: //my.service.local/1001" />
// get last error char* barberry_error(); // upload file to BarBerry's service and return ID int barberry_upload_file(const char *host, const char *filename); // download file from BarBerry's service by ID int barberry_download_file(const char *host, int id, const char *filename); // delete file from BarBerry's service by ID int barberry_delete_file(const char *host, int id);
char last_error[1024]; FILE *file = NULL; int result = 0;
int barberry_upload_file(const char *host, const char *filename) { result = -1; curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, host); struct curl_httppost *httppost = NULL; struct curl_httppost *last_ptr = NULL; curl_formadd(&httppost, &last_ptr, CURLFORM_COPYNAME, "sendfile", CURLFORM_FILE, filename, CURLFORM_END); curl_formadd(&httppost, &last_ptr, CURLFORM_COPYNAME, "submit", CURLFORM_COPYCONTENTS, "send", CURLFORM_END); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, upload_response); curl_easy_setopt(curl, CURLOPT_HTTPPOST, httppost); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { sprintf(last_error, "%s", curl_easy_strerror(res)); } curl_easy_cleanup(curl); curl_formfree(httppost); } return result; }
size_t function(char *ptr, size_t size, size_t nmemb, void *userdata);
size_t upload_response(char *ptr, size_t size, size_t nmemb, void *userdata) { (void)userdata; parse_upload_response(ptr); return size * nmemb; }
void parse_upload_response(const char *text) { if (!strcmp(text, "{}")) { sprintf(last_error, "%s", "Empty file"); return; } json_error_t error; json_t *root = json_loads(text, 0, &error); if (!root) { sprintf(last_error, "%s", text); return; } json_t *id = json_object_get(root, "id"); if(!json_is_integer(id)) { sprintf(last_error, "%s", text); json_decref(root); return; } result = json_integer_value(id); json_decref(root); }
int barberry_download_file(const char *host, int id, const char *filename) { result = 0; file = fopen(filename, "wb"); if (!file) { sprintf(last_error, "%s", "Can't create file"); return -1; } curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init(); if (curl) { char buffer[1024]; sprintf(buffer, "%s/%d", host, id); curl_easy_setopt(curl, CURLOPT_URL, buffer); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_response); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { sprintf(last_error, "%s", curl_easy_strerror(res)); result = -1; } curl_easy_cleanup(curl); } fclose(file); return result; }
size_t download_response(char *ptr, size_t size, size_t nmemb, void *userdata) { (void)userdata; if (!strcmp(ptr, "{}")) { sprintf(last_error, "%s", "File on server not found"); result = -1; } else { fwrite(ptr, size * nmemb, 1, file); } return size * nmemb; }
int barberry_delete_file(const char *host, int id) { result = 0; curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init(); if (curl) { char buffer[1024]; sprintf(buffer, "%s/%d", host, id); curl_easy_setopt(curl, CURLOPT_URL, buffer); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, delete_response); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { sprintf(last_error, "%s", curl_easy_strerror(res)); result = -1; } curl_easy_cleanup(curl); } return result; }
size_t delete_response(char *ptr, size_t size, size_t nmemb, void *userdata) { (void)ptr; (void)userdata; return size * nmemb; }
#include "barberry_impl.h" void print_help() { fprintf(stdout, "Usage:\n"); fprintf(stdout, " bbtest upload my.service.local /home/username/image1000.png\n"); fprintf(stdout, " bbtest download my.service.local 1000 /home/username/image1000.png\n"); fprintf(stdout, " bbtest delete my.service.local 1000\n\n"); } int main(int argc, char *argv[]) { (void)argc; (void)argv; if (argc <= 2) { print_help(); return 0; } if (!strcmp(argv[1], "upload")) { if (argc != 4) { print_help(); return 0; } int id = barberry_upload_file(argv[2], argv[3]); if (id != -1) { fprintf(stdout, "File uploaded with id %d\n", id); } else { fprintf(stderr, "%s\n", barberry_error()); } } else if (!strcmp(argv[1], "download")) { if (argc != 5) { print_help(); return 0; } int result = barberry_download_file(argv[2], atoi(argv[3]), argv[4]); if (result != -1) { fprintf(stdout, "%s\n", "File downloaded"); } else { fprintf(stderr, "%s\n", barberry_error()); } } else if (!strcmp(argv[1], "delete")) { if (argc != 4) { print_help(); return 0; } int result = barberry_delete_file(argv[2], atoi(argv[3])); if (result != -1) { fprintf(stdout, "%s\n", "File deleted"); } else { fprintf(stderr, "%s\n", barberry_error()); } } else { print_help(); } return 0; }
cc -c barberry_impl.c cc -c barberry_test.c cc -L/usr/lib -lcurl -ljansson -o bbtest barberry_test.o barberry_impl.o ./bbtest upload my.service.local ~/picture01.png File uploaded with id 1017
PG_FUNCTION_INFO_V1(bb_upload_file); PG_FUNCTION_INFO_V1(bb_download_file); PG_FUNCTION_INFO_V1(bb_delete_file);
char* text_to_string(text *txt) { size_t size = VARSIZE(txt) - VARHDRSZ; char *buffer = (char*)palloc(size + 1); memcpy(buffer, VARDATA(txt), size); buffer[size] = '\0'; return buffer; }
Datum bb_upload_file(PG_FUNCTION_ARGS) { char *host = text_to_string(PG_GETARG_TEXT_P(0)); char *filename = text_to_string(PG_GETARG_TEXT_P(1)); int result = barberry_upload_file(host, filename); if (result == -1) { elog(ERROR, "%s", barberry_error()); } pfree(host); pfree(filename); PG_RETURN_INT32(result); }
Datum bb_download_file(PG_FUNCTION_ARGS) { char *host = text_to_string(PG_GETARG_TEXT_P(0)); int id = PG_GETARG_INT32(1); char *filename = text_to_string(PG_GETARG_TEXT_P(2)); int result = barberry_download_file(host, id, filename); if (result == -1) { elog(ERROR, "%s", barberry_error()); } pfree(host); pfree(filename); PG_RETURN_VOID(); }
Datum bb_delete_file(PG_FUNCTION_ARGS) { char *host = text_to_string(PG_GETARG_TEXT_P(0)); int id = PG_GETARG_INT32(1); int result = barberry_delete_file(host, id); if (result == -1) { elog(ERROR, "%s", barberry_error()); } pfree(host); PG_RETURN_VOID(); }
rm -rf *.o cc -I/usr/include/postgresql/server -fpic -c barberry.c cc -I/usr/include/postgresql/server -fpic -c barberry_impl.c cc -L/usr/lib -lpq -lcurl -ljansson -shared -o barberry.so barberry.o barberry_impl.o cp *.so /usr/lib/postgresql
CREATE OR REPLACE FUNCTION public.bb_upload_file ( p_host text, p_filename text ) RETURNS integer AS 'barberry', 'bb_upload_file' LANGUAGE c VOLATILE STRICT; CREATE OR REPLACE FUNCTION public.bb_download_file ( p_host text, p_id integer, p_filename text ) RETURNS void AS 'barberry', 'bb_download_file' LANGUAGE c VOLATILE STRICT; CREATE OR REPLACE FUNCTION public.bb_delete_file ( p_host text, p_id integer ) RETURNS void AS 'barberry', 'bb_delete_file' LANGUAGE c VOLATILE STRICT;
# BarBerry image service comment = 'BarBerry image service' default_version = '1.0' module_pathname = '$libdir/barberry' relocatable = true
CREATE EXTENSION barberry; UPDATE avatar SET image = bb_upload_file ( 'my.service.local', 'images/avatar_admin.png' ) WHERE name = 'admin';
#ifndef BARBERRY_IMPL_H #define BARBERRY_IMPL_H #include <stdio.h> #include <string.h> #include <curl/curl.h> #include <jansson.h> // get last error char* barberry_error(); // upload file to BarBerry's service and return ID int barberry_upload_file(const char *host, const char *filename); // download file from BarBerry's service by ID int barberry_download_file(const char *host, int id, const char *filename); // delete file from BarBerry's service by ID int barberry_delete_file(const char *host, int id); #endif // BARBERRY_IMPL_H
#include "barberry_impl.h" char last_error[1024]; FILE *file = NULL; int result = 0; void parse_upload_response(const char *text) { if (!strcmp(text, "{}")) { sprintf(last_error, "%s", "Empty file"); return; } json_error_t error; json_t *root = json_loads(text, 0, &error); if (!root) { sprintf(last_error, "%s", text); return; } json_t *id = json_object_get(root, "id"); if(!json_is_integer(id)) { sprintf(last_error, "%s", text); json_decref(root); return; } result = json_integer_value(id); json_decref(root); } size_t upload_response(char *ptr, size_t size, size_t nmemb, void *userdata) { (void)userdata; parse_upload_response(ptr); return size * nmemb; } size_t download_response(char *ptr, size_t size, size_t nmemb, void *userdata) { (void)userdata; if (!strcmp(ptr, "{}")) { sprintf(last_error, "%s", "File on server not found"); result = -1; } else { fwrite(ptr, size * nmemb, 1, file); } return size * nmemb; } size_t delete_response(char *ptr, size_t size, size_t nmemb, void *userdata) { (void)ptr; (void)userdata; return size * nmemb; } char* barberry_error() { return last_error; } int barberry_upload_file(const char *host, const char *filename) { result = -1; curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, host); struct curl_httppost *httppost = NULL; struct curl_httppost *last_ptr = NULL; curl_formadd(&httppost, &last_ptr, CURLFORM_COPYNAME, "sendfile", CURLFORM_FILE, filename, CURLFORM_END); curl_formadd(&httppost, &last_ptr, CURLFORM_COPYNAME, "submit", CURLFORM_COPYCONTENTS, "send", CURLFORM_END); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, upload_response); curl_easy_setopt(curl, CURLOPT_HTTPPOST, httppost); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { sprintf(last_error, "%s", curl_easy_strerror(res)); } curl_easy_cleanup(curl); curl_formfree(httppost); } return result; } int barberry_download_file(const char *host, int id, const char *filename) { result = 0; file = fopen(filename, "wb"); if (!file) { sprintf(last_error, "%s", "Can't create file"); return -1; } curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init(); if (curl) { char buffer[1024]; sprintf(buffer, "%s/%d", host, id); curl_easy_setopt(curl, CURLOPT_URL, buffer); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_response); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { sprintf(last_error, "%s", curl_easy_strerror(res)); result = -1; } curl_easy_cleanup(curl); } fclose(file); return result; } int barberry_delete_file(const char *host, int id) { result = 0; curl_global_init(CURL_GLOBAL_ALL); CURL *curl = curl_easy_init(); if (curl) { char buffer[1024]; sprintf(buffer, "%s/%d", host, id); curl_easy_setopt(curl, CURLOPT_URL, buffer); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, delete_response); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { sprintf(last_error, "%s", curl_easy_strerror(res)); result = -1; } curl_easy_cleanup(curl); } return result; }
#include <postgres.h> #include <fmgr.h> #include "barberry_impl.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1(bb_upload_file); PG_FUNCTION_INFO_V1(bb_download_file); PG_FUNCTION_INFO_V1(bb_delete_file); char* text_to_string(text *txt) { size_t size = VARSIZE(txt) - VARHDRSZ; char *buffer = (char*)palloc(size + 1); memcpy(buffer, VARDATA(txt), size); buffer[size] = '\0'; return buffer; } Datum bb_upload_file(PG_FUNCTION_ARGS) { char *host = text_to_string(PG_GETARG_TEXT_P(0)); char *filename = text_to_string(PG_GETARG_TEXT_P(1)); int result = barberry_upload_file(host, filename); if (result == -1) { elog(ERROR, "%s", barberry_error()); } pfree(host); pfree(filename); PG_RETURN_INT32(result); } Datum bb_download_file(PG_FUNCTION_ARGS) { char *host = text_to_string(PG_GETARG_TEXT_P(0)); int id = PG_GETARG_INT32(1); char *filename = text_to_string(PG_GETARG_TEXT_P(2)); int result = barberry_download_file(host, id, filename); if (result == -1) { elog(ERROR, "%s", barberry_error()); } pfree(host); pfree(filename); PG_RETURN_VOID(); } Datum bb_delete_file(PG_FUNCTION_ARGS) { char *host = text_to_string(PG_GETARG_TEXT_P(0)); int id = PG_GETARG_INT32(1); int result = barberry_delete_file(host, id); if (result == -1) { elog(ERROR, "%s", barberry_error()); } pfree(host); PG_RETURN_VOID(); }
#include "barberry_impl.h" void print_help() { fprintf(stdout, "Usage:\n"); fprintf(stdout, " bbtest upload my.service.local /home/username/image1000.png\n"); fprintf(stdout, " bbtest download my.service.local 1000 /home/username/image1000.png\n"); fprintf(stdout, " bbtest delete my.service.local 1000\n\n"); } int main(int argc, char *argv[]) { (void)argc; (void)argv; if (argc <= 2) { print_help(); return 0; } if (!strcmp(argv[1], "upload")) { if (argc != 4) { print_help(); return 0; } int id = barberry_upload_file(argv[2], argv[3]); if (id != -1) { fprintf(stdout, "File uploaded with id %d\n", id); } else { fprintf(stderr, "%s\n", barberry_error()); } } else if (!strcmp(argv[1], "download")) { if (argc != 5) { print_help(); return 0; } int result = barberry_download_file(argv[2], atoi(argv[3]), argv[4]); if (result != -1) { fprintf(stdout, "%s\n", "File downloaded"); } else { fprintf(stderr, "%s\n", barberry_error()); } } else if (!strcmp(argv[1], "delete")) { if (argc != 4) { print_help(); return 0; } int result = barberry_delete_file(argv[2], atoi(argv[3])); if (result != -1) { fprintf(stdout, "%s\n", "File deleted"); } else { fprintf(stderr, "%s\n", barberry_error()); } } else { print_help(); } return 0; }
CREATE OR REPLACE FUNCTION public.bb_upload_file ( p_host text, p_filename text ) RETURNS integer AS 'barberry', 'bb_upload_file' LANGUAGE c VOLATILE STRICT; CREATE OR REPLACE FUNCTION public.bb_download_file ( p_host text, p_id integer, p_filename text ) RETURNS void AS 'barberry', 'bb_download_file' LANGUAGE c VOLATILE STRICT; CREATE OR REPLACE FUNCTION public.bb_delete_file ( p_host text, p_id integer ) RETURNS void AS 'barberry', 'bb_delete_file' LANGUAGE c VOLATILE STRICT
# BarBerry image service comment = 'BarBerry image service' default_version = '1.0' module_pathname = '$libdir/barberry' relocatable = true
################################# # Makefile for barberry library # ################################# # options CC=cc CFLAGS=-fpic -c INCLUDEPATH=-I/usr/include/postgresql/server LIBS=-L/usr/lib -lpq -lcurl -ljansson # targets all: barberry barberry_test barberry: barberry.o barberry_impl.o $(CC) $(LIBS) -shared -o barberry.so barberry.o barberry_impl.o barberry_test: barberry_test.o barberry_impl.o $(CC) $(LIBS) -o bbtest barberry_test.o barberry_impl.o barberry.o: $(CC) $(INCLUDEPATH) $(CFLAGS) barberry.c barberry_impl.o: $(CC) $(INCLUDEPATH) $(CFLAGS) barberry_impl.c barberry_test.o: $(CC) $(INCLUDEPATH) $(CFLAGS) barberry_test.c clean: rm -rf *.o *.so bbtest rebuild: clean all install: cp *.so /usr/lib/postgresql cp *.control /usr/share/postgresql/extension cp *.sql /usr/share/postgresql/extension
Source: https://habr.com/ru/post/206576/
All Articles