diff options
| author | ꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id> | 2021-06-27 23:41:31 +0800 | 
|---|---|---|
| committer | ꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id> | 2021-06-27 23:41:31 +0800 | 
| commit | 65a334cf2fe2d7d524c129f0df765463a91f542c (patch) | |
| tree | d182a3e1b474dfd9329357154a1a618a199cdebb | |
Shipping API client framework
with 1 module so far.
| -rw-r--r-- | .gitignore | 22 | ||||
| -rw-r--r-- | COPYING | 20 | ||||
| -rw-r--r-- | Makefile.am | 6 | ||||
| -rw-r--r-- | README.md | 14 | ||||
| -rw-r--r-- | anteraja.c | 45 | ||||
| -rw-r--r-- | configure.ac | 13 | ||||
| -rw-r--r-- | handler.c | 13 | ||||
| -rw-r--r-- | handler.h | 67 | ||||
| -rw-r--r-- | pikul.c | 102 | ||||
| -rw-r--r-- | pikul.h | 35 | ||||
| -rw-r--r-- | shipping.c | 12 | ||||
| -rw-r--r-- | shipping.h | 10 | 
12 files changed, 359 insertions, 0 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc14edf --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +.deps +.libs +*.la +*.lo +*.o +*.swp +aclocal.m4 +autoscan-2.69.log +ar-lib +autom4te.cache +build* +compile +config.* +configure +depcomp +install-sh +libtool +ltmain.sh +Makefile +Makefile.in +missing +stamp-h1 @@ -0,0 +1,20 @@ +Copyright (c) 2021 Erik Prabowo Kamal + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..5d8f4d7 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,6 @@ +lib_LTLIBRARIES = libpikul.la +libpikul_la_SOURCES = pikul.c shipping.c handler.c \ +		      anteraja.c +libpikul_la_CPPFLAGS = $(DEPS_CFLAGS) +libpikul_la_LDFLAGS = $(DEPS_LIBS) +include_HEADERS = pikul.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae5336b --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Pikul + +# Building + +```sh +$ git clone git://darapsa.org/libpikul.git +$ cd libpikul +$ autoreconf -is +$ mkdir build +$ cd build +$ ../configure +$ make # -jN +$ make install +``` diff --git a/anteraja.c b/anteraja.c new file mode 100644 index 0000000..cf9d685 --- /dev/null +++ b/anteraja.c @@ -0,0 +1,45 @@ +#include "shipping.h" +#include "handler.h" + +extern CURL *curl; + +void anteraja_init(char *provisions[], struct shipping *shipping) +{ +	shipping->base = malloc(strlen(*provisions) + 1); +	strcpy(shipping->base, *provisions); +	headers(shipping, (const char *[]){ "access-key-id", "secret-access-key", NULL }, ++provisions); +	shipping->headers = curl_slist_append(shipping->headers, "Content-Type:application/json"); +} + +void anteraja_services_request(const char *origin, const char *destination, double weight, +		struct shipping *shipping, char **url, char **post) +{ +	static const char *path = "serviceRates"; +	*url = malloc(strlen(shipping->base) + strlen(path) + 1); +	sprintf(*url, "%s%s", shipping->base, path); +	static const char *format = "{" +		"\"origin\": \"xx.xx.xx\"," +		"\"destination\": \"xx.xx.xx\"," +		"\"weight\": xxxxx" +		"}"; +	*post = malloc(strlen(format) + 1); +	sprintf(*post, "{\"origin\": \"%s\",\"destination\": \"%s\",\"weight\": %d}", +			origin, destination, (int)weight); +	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, *post); +} + +size_t anteraja_services_handle(const char *contents, size_t size, size_t nmemb, +		struct pikul_services **services) +{ +	size_t realsize = size * nmemb; +	handle(contents, realsize, &(struct container){ services, (const char *[]){ +		"product_code", +		"product_name", +		"etd", +		"rates", +		"content", +		"services", +		NULL +	}}); +	return realsize; +} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..c6d63c1 --- /dev/null +++ b/configure.ac @@ -0,0 +1,13 @@ +AC_INIT([pikul], [0.0], [pt@darapsa.co.id]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign]) +AC_PROG_CC +AM_PROG_AR +LT_INIT +PKG_CHECK_MODULES([DEPS], [libcurl json-c]) +AC_TYPE_SIZE_T +AC_C_INLINE +AC_FUNC_MALLOC +AC_CHECK_FUNCS([memset]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/handler.c b/handler.c new file mode 100644 index 0000000..581001e --- /dev/null +++ b/handler.c @@ -0,0 +1,13 @@ +#include "handler.h" + +extern inline void handle(const char *, size_t, struct container *); + +void recurse(struct json_object *outer, const char *keys[], struct json_object **services) +{ +	struct json_object *inner = NULL; +	json_object_object_get_ex(outer, *keys, &inner); +	if (*++keys) +		recurse(inner, keys, services); +	else +		*services = inner; +} diff --git a/handler.h b/handler.h new file mode 100644 index 0000000..9c80ab6 --- /dev/null +++ b/handler.h @@ -0,0 +1,67 @@ +#include <string.h> +#include <json.h> +#include "pikul.h" + +enum { +	KEY_CODE, +	KEY_NAME, +	KEY_ETD, +	KEY_COST, +	KEY_OBJECTS +}; + +struct container { +	struct pikul_services **services; +	const char **keys[7]; +}; + +extern json_tokener *tokener; +void recurse(struct json_object *, const char *[], struct json_object **); + +inline void handle(const char *contents, size_t num_bytes, struct container *container) +{ +	json_object *response = json_tokener_parse_ex(tokener, contents, num_bytes); +	enum json_tokener_error error = json_tokener_get_error(tokener); +	if (!response) { +		if (error == json_tokener_continue) +			return; +		else { +			json_tokener_reset(tokener); +			return; +		} +	} else if (!json_object_is_type(response, json_type_object) || error != json_tokener_success) +		return; +	struct json_object *services = NULL; +	recurse(response, &(*container->keys)[KEY_OBJECTS], &services); +	size_t length = json_object_array_length(services); +	*(container->services) = malloc(sizeof(struct pikul_services) +			+ sizeof(struct pikul_service *[length])); +	(*(container->services))->length = length; +	for (size_t i = 0; i < length; i++) { +		(*(container->services))->list[i] = malloc(sizeof(struct pikul_service)); +		struct pikul_service *service = (*(container->services))->list[i]; +		json_object *object = json_object_array_get_idx(services, i); +		struct json_object_iterator iterator = json_object_iter_begin(object); +		struct json_object_iterator iterator_end = json_object_iter_end(object); +		while (!json_object_iter_equal(&iterator, &iterator_end)) { +			const char *key = json_object_iter_peek_name(&iterator); +			json_object *val = json_object_iter_peek_value(&iterator); +			if (!strcmp(key, (*container->keys)[KEY_COST])) +				service->cost = json_object_get_double(val); +			else { +				int len = json_object_get_string_len(val); +				if (len) { +					char *value = malloc(len + 1); +					strcpy(value, json_object_get_string(val)); +					if (!strcmp(key, (*container->keys)[KEY_CODE])) +						service->code = value; +					else if (!strcmp(key, (*container->keys)[KEY_NAME])) +						service->name = value; +					else if (!strcmp(key, (*container->keys)[KEY_ETD])) +						service->etd = value; +				} +			} +			json_object_iter_next(&iterator); +		} +	} +} @@ -0,0 +1,102 @@ +#include <string.h> +#include <json.h> +#include "shipping.h" + +CURL *curl; +json_tokener *tokener; +static struct shipping shipping; + +extern void anteraja_init(char *[], struct shipping *); +extern void anteraja_services_request(const char *, const char *, double, +		struct shipping *, char **, char **); +extern size_t anteraja_services_handle(const char *, size_t, size_t, struct pikul_services **); + +void pikul_init(enum pikul_company company, char *provisions[]) +{ +	curl_global_init(CURL_GLOBAL_SSL); +	curl = curl_easy_init(); +#ifdef DEBUG +	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); +#endif +	shipping.company = company; +	switch (company) { +		case PIKUL_COMPANY_ANTERAJA: +			anteraja_init(provisions, &shipping); +			break; +		default: +			break; +	} +	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, shipping.headers); +	tokener = json_tokener_new(); +} + +struct pikul_services *pikul_services(const char *origin, const char *destination, double weight) +{ +	struct pikul_services *services = NULL; +	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &services); +	char *url; +	char *post = NULL; +	size_t (*handler)(const char *, size_t, size_t, struct pikul_services **); +	switch (shipping.company) { +		case PIKUL_COMPANY_ANTERAJA: +			anteraja_services_request(origin, destination, weight, &shipping, &url, &post); +			handler = anteraja_services_handle; +			break; +		default: +			break; +	} +	curl_easy_setopt(curl, CURLOPT_URL, url); +	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handler); +	curl_easy_perform(curl); +	if (post) +		free(post); +	free(url); +	return services; +} + +static inline void free_service(struct pikul_service *service) +{ +	if (service->etd) +		free(service->etd); +	if (service->name) +		free(service->name); +	free(service->code); +	free(service); +} + +void pikul_free_services(struct pikul_services *services) +{ +	for (size_t i = 0; i < services->length; i++) +		free_service(services->list[i]); +	free(services); +} + +static int servicecmp(const void *service1, const void *service2) +{ +	return strcmp((*(struct pikul_service * const *)service1)->code, +			(*(struct pikul_service * const *)service2)->code); +} + +double pikul_cost(const char *origin, const char *destination, double weight, const char *code) +{ +	struct pikul_services *services = pikul_services(origin, destination, weight); +	qsort(services->list, services->length, sizeof(struct pikul_service *), servicecmp); +	struct pikul_service *key_service = malloc(sizeof(struct pikul_service)); +	memset(key_service, '\0', sizeof(struct pikul_service)); +	key_service->code = malloc(strlen(code) + 1); +	strcpy(key_service->code, code); +	double cost = (*(struct pikul_service **)bsearch(&key_service, services->list, +				services->length, sizeof(struct pikul_service *), servicecmp))->cost; +	free_service(key_service); +	pikul_free_services(services); +	return cost; +} + +void pikul_cleanup() +{ +	free(shipping.base); +	json_tokener_free(tokener); +	curl_slist_free_all(shipping.headers); +	curl_easy_cleanup(curl); +	curl_global_cleanup(); +} @@ -0,0 +1,35 @@ +#ifndef PIKUL_H +#define PIKUL_H + +enum pikul_company { +	PIKUL_COMPANY_ANTERAJA = 0, +	PIKUL_COMPANY_SICEPAT +}; + +struct pikul_service { +	char *code; +	char *name; +	char *etd; +	double cost; +}; + +struct pikul_services { +	size_t length; +	struct pikul_service *list[]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +void pikul_init(enum pikul_company company, char *provisions[]); +struct pikul_services *pikul_services(const char *origin, const char *destination, double weight); +void pikul_free_services(struct pikul_services *services); +double pikul_cost(const char *origin, const char *destination, double weight, const char *service); +void pikul_cleanup(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/shipping.c b/shipping.c new file mode 100644 index 0000000..f2e263c --- /dev/null +++ b/shipping.c @@ -0,0 +1,12 @@ +#include <string.h> +#include "shipping.h" + +void headers(struct shipping *shipping, const char *fields[], char *provisions[]) +{ +	shipping->headers = NULL; +	while (*fields) { +		char header[strlen(*fields) + strlen(*provisions) + 2]; +		sprintf(header, "%s:%s", *fields++, *provisions++); +		shipping->headers = curl_slist_append(shipping->headers, header); +	} +} diff --git a/shipping.h b/shipping.h new file mode 100644 index 0000000..345eaef --- /dev/null +++ b/shipping.h @@ -0,0 +1,10 @@ +#include <curl/curl.h> +#include "pikul.h" + +struct shipping { +	enum pikul_company company; +	char *base; +	struct curl_slist *headers; +}; + +void headers(struct shipping *, const char *[], char *[]); |