grim/purple-spasm

Move the parsing to regex and make real_send add the trailing \r\n
/*
* Spasm - A Twitch Protocol Plugin
* Copyright (C) 2017-2019 Gary Kramlich <grim@reaperworld.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <libsoup/soup.h>
#include <purple.h>
#include "spasm.h"
#include "spasm-const.h"
#include "spasm-rest.h"
/******************************************************************************
* Types
*****************************************************************************/
typedef struct {
SpasmAccount *sa;
SpasmRestCallback cb;
gpointer data;
} SpasmRestCallbackData;
/******************************************************************************
* Callbacks
*****************************************************************************/
static void
spasm_request_cb(GObject *obj, GAsyncResult *res, gpointer data) {
GInputStream *istream = NULL;
GError *error = NULL;
JsonParser *parser = NULL;
JsonNode *root = NULL;
JsonObject *json_obj = NULL;
SpasmRestCallbackData *cb_data = (SpasmRestCallbackData *)data;
istream = soup_session_send_finish(SOUP_SESSION(obj), res, &error);
if(error) {
cb_data->cb(cb_data->sa, NULL, error, cb_data->data);
g_free(cb_data);
return;
}
parser = json_parser_new();
json_parser_load_from_stream(parser, istream, NULL, &error);
if(error) {
cb_data->cb(cb_data->sa, NULL, error, cb_data->data);
g_free(cb_data);
g_object_unref(G_OBJECT(parser));
return;
}
root = json_parser_get_root(parser);
if(root == NULL || !JSON_NODE_HOLDS_OBJECT(root)) {
error = g_error_new(
SPASM_DOMAIN,
0,
"invalid json response"
);
cb_data->cb(cb_data->sa, NULL, error, cb_data->data);
g_error_free(error);
g_free(cb_data);
g_object_unref(G_OBJECT(parser));
return;
}
json_obj = json_node_get_object(root);
if(json_obj == NULL) {
error = g_error_new(
SPASM_DOMAIN,
0,
"json is not an object"
);
cb_data->cb(cb_data->sa, NULL, error, cb_data->data);
g_error_free(error);
g_free(cb_data);
g_object_unref(G_OBJECT(parser));
return;
}
if(json_object_has_member(json_obj, "error")) {
purple_debug_info("spasm", "error: %s\n", json_object_get_string_member(json_obj, "error"));
error = g_error_new(
SPASM_DOMAIN,
0,
"error : %s : %" G_GINT64_FORMAT,
json_object_get_string_member(json_obj, "message"),
json_object_get_int_member(json_obj, "status")
);
cb_data->cb(cb_data->sa, NULL, error, cb_data->data);
g_error_free(error);
g_free(cb_data);
g_object_unref(G_OBJECT(parser));
return;
}
cb_data->cb(cb_data->sa, parser, NULL, cb_data->data);
g_object_unref(G_OBJECT(parser));
}
/******************************************************************************
* API
*****************************************************************************/
void
spasm_rest_request(SpasmAccount *sa, const gchar *method,
const gchar *path, const gchar *body,
SpasmRestCallback callback, gpointer data)
{
SpasmRestCallbackData *cb;
SoupMessage *msg = NULL;
SoupSession *session = NULL;
gchar *url = NULL, *auth = NULL;
g_return_if_fail(sa);
url = g_build_filename(SPASM_BASE_URL, path, NULL);
msg = soup_message_new(method, url);
g_free(url);
// Set the Client-ID header
soup_message_headers_replace(
msg->request_headers,
"Client-ID",
SPASM_OAUTH2_CLIENT_ID
);
// Set the Accept header
soup_message_headers_replace(
msg->request_headers,
"Accept",
SPASM_CONTENT_TYPE
);
// Set the authorization header to the access token
auth = g_strdup_printf("OAuth %s", spasm_account_get_access_token(sa));
soup_message_headers_replace(
msg->request_headers,
"Authorization", auth
);
g_free(auth);
cb = g_new0(SpasmRestCallbackData, 1);
cb->sa = sa;
cb->cb = callback;
cb->data = data;
session = spasm_account_get_session(sa);
soup_session_send_async(
session,
msg,
spasm_account_get_cancellable(sa),
spasm_request_cb,
cb
);
g_object_unref(G_OBJECT(session));
}