changethe XML network IO to formally to be a backend plugin.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3431 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 2001-01-10 18:51:39 +00:00
parent 4c8b980884
commit 2f4edaef66
9 changed files with 246 additions and 110 deletions

View File

@ -16,6 +16,7 @@
#include "Account.h"
#include "Group.h"
#include "Query.h"
#include "Transaction.h"
#include "gnc-book.h"
@ -32,13 +33,15 @@ typedef struct _backend Backend;
struct _backend
{
AccountGroup * (*book_begin) (GNCBook *, const char * book_id);
AccountGroup * (*book_load) (GNCBook *, const char * book_id);
int (*book_end) (GNCBook *);
int (*account_begin_edit) (Backend *, Account *, int defer);
int (*account_commit_edit) (Backend *, Account *);
int (*trans_begin_edit) (Backend *, Transaction *);
int (*trans_commit_edit) (Backend *, Transaction *new, Transaction *orig);
int (*trans_rollback_edit) (Backend *, Transaction *);
int (*run_query) (Backend *, Query *);
};
/*

View File

@ -22,8 +22,11 @@
\********************************************************************/
/*
* ultra super reudimentary right now
* this will be very very different in final verisn
* ultra super rudimentary right now
* HACK ALRT -- this should be moved into its own sbdirectory
* Mostly so that the engine build doesn't require libghttp
* as a dependency.
*/
@ -33,25 +36,50 @@
#include <stdlib.h>
#include <string.h>
#include "BackendP.h"
#include "NetIO.h"
#include "gnc-book.h"
#include "gnc-engine-util.h"
#include "io-gncxml.h"
static short module = MOD_IO;
/* ==================================================================== */
typedef struct _xmlend XMLBackend;
AccountGroup *
xaccRecvAccountGroup (char *url)
struct _xmlend {
Backend be;
ghttp_request *request;
char * query_url;
};
Backend *xmlendNew (void);
/* ==================================================================== */
/* Load a set of accounts and currencies from the indicated URL. */
static AccountGroup *
xmlbeBookLoad (GNCBook *book, const char *url)
{
XMLBackend *be;
AccountGroup *grp;
ghttp_request *request;
char *bufp;
int len;
if (!book) return NULL;
ENTER ("url is %s\n", url);
request = ghttp_request_new();
ghttp_set_uri (request, url);
be = (XMLBackend *) xaccGNCBookGetBackend (book);
/* hack alert -- some bogus url for sending queries to */
/* this should be made customizable, I suppose ???? */
be->query_url = g_strdup (url);
request = be->request;
ghttp_set_uri (request, (char *) url);
ghttp_set_type (request, ghttp_type_get);
ghttp_set_header (request, http_hdr_Connection, "close");
ghttp_set_sync (request, ghttp_sync);
@ -71,18 +99,110 @@ xaccRecvAccountGroup (char *url)
}
else
{
char * errstr = ghttp_get_error (request);
char * reason = ghttp_reason_phrase (request);
const char * errstr = ghttp_get_error (request);
const char * reason = ghttp_reason_phrase (request);
PERR ("connection failed: %s %s\n", errstr, reason);
ghttp_request_destroy(request);
return NULL;
}
ghttp_request_destroy(request);
LEAVE("\n");
return NULL;
}
/* ==================================================================== */
static int
xmlbeRunQuery (Backend *b, Query *q)
{
XMLBackend *be = (XMLBackend *) b;
ghttp_request *request;
char *bufp;
int len;
if (!be || !q) return 999;
/* set up a new http request, of type POST */
request = ghttp_request_new();
ghttp_set_uri (request, be->query_url);
ghttp_set_type (request, ghttp_type_post);
ghttp_set_header (request, http_hdr_Connection, "close");
ghttp_set_sync (request, ghttp_sync);
ghttp_clean (request);
/* convert the query to XML */
gncxml_write_query_to_buf (q, &bufp, &len);
/* put the XML into the request body */
ghttp_set_body (request, bufp, len);
/* send it off the the webserver, wait for the reply */
ghttp_prepare (request);
ghttp_process (request);
/* free the query xml */
free (bufp);
len = ghttp_get_body_len(request);
if (0 < len)
{
bufp = ghttp_get_body(request);
PINFO ("reply length=%d\n", len);
DEBUG ("%s\n", bufp);
/* we got back a list of splits, these need to be merged in */
// grp = gncxml_read_from_buf (bufp, len);
return 0;
}
else
{
const char * errstr = ghttp_get_error (request);
const char * reason = ghttp_reason_phrase (request);
PERR ("connection failed: %s %s\n", errstr, reason);
return 444;
}
LEAVE("\n");
return 0;
}
/* ==================================================================== */
#if 0
xmlbeBookEnd ()
{
ghttp_request_destroy (be->request);
g_free (be->query_url);
}
#endif
/* ==================================================================== */
Backend *
xmlendNew (void)
{
XMLBackend *be;
be = (XMLBackend *) malloc (sizeof (XMLBackend));
/* generic backend handlers */
be->be.book_load = xmlbeBookLoad;
be->be.book_end = NULL;
be->be.account_begin_edit = NULL;
be->be.account_commit_edit = NULL;
be->be.trans_begin_edit = NULL;
be->be.trans_commit_edit = NULL;
be->be.trans_rollback_edit = NULL;
be->be.run_query = xmlbeRunQuery;
be->request = ghttp_request_new();
be->query_url = NULL;
return (Backend *) be;
}
/* ============================== END OF FILE ======================== */

View File

@ -25,8 +25,8 @@
#ifndef __XACC_NET_IO_H__
#define __XACC_NET_IO_H__
#include "Group.h"
#include "BackendP.h"
AccountGroup * xaccRecvAccountGroup (char *url);
Backend * xmlendNew (void);
#endif /* __XACC_NET_IO_H__ */

View File

@ -22,23 +22,24 @@
#include <ctype.h>
#include <glib.h>
#include <sys/types.h>
#include <math.h>
#include <string.h>
#include <regex.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "gnc-common.h"
#include "gnc-engine-util.h"
#include "gnc-numeric.h"
#include "TransactionP.h"
#include "Transaction.h"
#include "Account.h"
#include "BackendP.h"
#include "Group.h"
#include "Query.h"
#include "Transaction.h"
#include "TransactionP.h"
static short module = MOD_QUERY;
@ -955,12 +956,14 @@ xaccQueryGetSplits(Query * q) {
GList * all_accts, * node;
Account * current;
QueryTerm * qt;
Backend * be;
int total_splits_checked = 0;
int split_count = 0;
int acct_ok;
if (!q) return NULL;
ENTER("query=%p", q);
/* tmp hack alert */
q->changed = 1;
@ -982,6 +985,12 @@ xaccQueryGetSplits(Query * q) {
/* prepare the terms for processing */
xaccQueryCompileTerms (q);
/* if there is a backend, query the backend, let it fetch the data */
be = xaccGroupGetBackend (q->acct_group);
if (be && be->run_query) {
(be->run_query) (be, q);
}
/* iterate over accounts */
all_accts = xaccGroupGetSubAccounts (q->acct_group);
@ -2165,6 +2174,15 @@ xaccQuerySetGroup(Query * q, AccountGroup * g) {
}
/*******************************************************************
* xaccQueryGetGroup
*******************************************************************/
AccountGroup *
xaccQueryGetGroup(Query * q) {
return (q->acct_group);
}
/*******************************************************************
* xaccQueryGetEarliestDateFound
*******************************************************************/

View File

@ -206,20 +206,23 @@ typedef struct {
* basic Query API
*******************************************************************/
Query * xaccMallocQuery(void);
void xaccFreeQuery(Query *);
Query * xaccQueryCopy(Query *q);
void xaccQuerySetGroup(Query * q, AccountGroup * group);
Query * xaccQueryInvert(Query * q1);
Query * xaccQueryMerge(Query * q1, Query * q2, QueryOp op);
void xaccQueryClear(Query * q);
void xaccQueryPurgeTerms(Query * q, pd_type_t type);
Query * xaccMallocQuery(void);
void xaccFreeQuery(Query *);
Query * xaccQueryCopy(Query *q);
void xaccQuerySetGroup(Query * q, AccountGroup * group);
AccountGroup *xaccQueryGetGroup(Query * q);
int xaccQueryHasTerms(Query * q);
gboolean xaccQueryHasTermType(Query * q, pd_type_t type);
GList * xaccQueryGetTerms(Query * q);
Query * xaccQueryInvert(Query * q1);
Query * xaccQueryMerge(Query * q1, Query * q2, QueryOp op);
void xaccQueryClear(Query * q);
GList * xaccQueryGetSplits(Query * q);
void xaccQueryPurgeTerms(Query * q, pd_type_t type);
int xaccQueryHasTerms(Query * q);
gboolean xaccQueryHasTermType(Query * q, pd_type_t type);
GList * xaccQueryGetTerms(Query * q);
/* after the query has been set up, call this to run the query */
GList * xaccQueryGetSplits(Query * q);
/* handy for debugging */
void xaccQueryPrint(Query *q);

View File

@ -83,7 +83,8 @@ struct _gnc_book
int lockfd;
/* ---------------------------------------------------- */
/* this struct member applies only for SQL i/o */
/* This struct member applies for network and SQL i/o */
/* It is not currently used for file i/o, but maybe it should be ?? */
Backend *backend;
};
@ -176,39 +177,6 @@ gnc_book_get_file_path (GNCBook *book)
/* ============================================================== */
#if 0
static AccountGroup *
xaccSessionBeginSQL (Session *sess, const char * dbname)
{
Backend *be = NULL;
AccountGroup *grp = NULL;
if (!sess) return NULL;
/* #define SQLHACK */
#ifdef SQLHACK
{
/* for testing the sql, just a hack, remove later ... */
extern Backend * pgendNew (void);
be = pgendNew ();
}
#endif
sess->backend = be;
if (be && be->session_begin) {
grp = (be->session_begin) (sess, dbname);
}
/* comment out until testing done, else clobber file ...*/
/* sess->topgroup = grp; */
xaccGroupSetBackend (sess->topgroup, be);
return (sess->topgroup);
}
#endif
/* ============================================================== */
static gboolean
gnc_book_get_file_lock (GNCBook *book)
{
@ -318,21 +286,6 @@ gnc_book_begin_file (GNCBook *book, const char * filefrag,
return TRUE;
}
/* ============================================================== */
/* URL mostly a noop --- maybe this would be a login dialog ??? */
static gboolean
gnc_book_begin_http (GNCBook *book, const char * pathfrag)
{
ENTER ("pathfrag=%s\n", pathfrag);
/* Store the sessionid URL */
book->book_id = g_strdup (pathfrag);
LEAVE ("\n");
return TRUE;
}
/* ============================================================== */
gboolean
@ -369,24 +322,45 @@ gnc_book_begin (GNCBook *book, const char * book_id, gboolean ignore_lock)
return rc;
}
if (!strncmp(book_id, "http://", 7))
/* -------------------------------------------------- */
if ((!strncmp(book_id, "http://", 7)) ||
(!strncmp(book_id, "https://", 8)))
{
rc = gnc_book_begin_http (book, book_id);
return rc;
}
if (!strncmp(book_id, "https://", 8))
{
rc = gnc_book_begin_http (book, book_id);
return rc;
/* Store the sessionid URL */
book->book_id = g_strdup (book_id);
/* create the backend */
book->backend = xmlendNew();
/* not sure what else should happen here ... should we check to see
* if the URL is reachable ?? Should we login the user ??
*/
return TRUE;
}
/* -------------------------------------------------- */
if (!strncmp(book_id, "postgres://", 11))
{
/* Store the sessionid URL */
/* we expect this to be in the format
* postgres://some.hostname.com/databasename.pql
* or maybe
* postgres://localhost/databasename.pql
* or one can specify the postgres socket port number explicitly:
* postgres://some.hostname.com:5432/databasename.pql
*/
book->book_id = g_strdup (book_id);
/* #define SQLHACK */
#ifdef SQLHACK
extern Backend * pgendNew (void);
book->backend = pgendNew ();
#endif
book->errtype = ENOSYS;
return FALSE;
}
/* -------------------------------------------------- */
/* otherwise, lets just assume its a file. */
@ -436,14 +410,34 @@ gnc_book_load (GNCBook *book)
LEAVE("\n");
return TRUE;
}
else if (strncmp(book->book_id, "http://", 7) == 0)
else if ((strncmp(book->book_id, "http://", 7) == 0) ||
(strncmp(book->book_id, "https://", 8) == 0) ||
(strncmp(book->book_id, "postgres://", 11) == 0))
{
/* This code should be sufficient to initiliaze *any* backend,
* whether http, postgres, or anything else that might come along.
* Basically, the idea is that by now, a backend has already been
* created & set up. At this point, we only need to get the
* top-level account group out of the backend, and that is a
* generic, backend-independent operation.
*/
Backend *be = book->backend;
xaccFreeAccountGroup (book->topgroup);
book->topgroup = NULL;
book->errtype = 0;
book->last_file_err = ERR_FILEIO_NONE;
book->topgroup = xaccRecvAccountGroup (book->book_id);
/* starting the session should result in a bunch of accounts
* and currencies being downloaded, but probably no transactions;
* The GUI will need to do a query for that.
*/
if (be && be->book_load) {
book->topgroup = (be->book_load) (book, book->book_id);
}
xaccGroupSetBackend (book->topgroup, be);
if (!book->topgroup || (book->last_file_err != ERR_FILEIO_NONE))
{
@ -454,16 +448,6 @@ gnc_book_load (GNCBook *book)
LEAVE("\n");
return TRUE;
}
else if (strncmp(book->book_id, "postgres://", 11) == 0)
{
#ifdef SQLHACK
/* for testing the sql, just a hack, remove later ... */
/* this should never ever appear here ... */
xaccSessionBeginSQL (sess, book->book_id);
#endif
book->errtype = ENOSYS;
return FALSE;
}
else
{
book->errtype = ENOSYS;

View File

@ -904,14 +904,15 @@ pgendNew (void)
be = (PGBackend *) malloc (sizeof (PGBackend));
/* generic backend handlers */
be->be.session_begin = pgend_session_begin;
be->be.session_end = NULL;
be->be.book_load = pgend_session_begin;
be->be.book_end = NULL;
be->be.account_begin_edit = NULL;
be->be.account_commit_edit = NULL;
be->be.trans_begin_edit = NULL;
be->be.trans_commit_edit = pgend_trans_commit_edit;
be->be.trans_rollback_edit= NULL;
be->be.run_query= NULL;
/* postgres specific data */
be->dbName = NULL;

View File

@ -1,7 +1,7 @@
/*
* PostgressBackend.h
* PostgresBackend.h
*
* Implements the callbacks for the postgress backend.
* Implements the callbacks for the postgres backend.
*
*/

View File

@ -1,9 +1,9 @@
This directory contains very broken, very experimental code
for sql support. It doesn't work. The instructions bwlow are for
for sql support. It doesn't work. The instructions below are for
developers who want to hack this code.
1) Install postgresl server, client and devel packages.
1) Install postgresql server, client and devel packages.
2) if installed from redhat, then running /etc/rc.d/init.d/postgresql
will setup and initialize all first-time setup & config.
3) as root, su - postgres then run 'createuser' to add your user id
@ -17,7 +17,14 @@ developers who want to hack this code.
Development Notes
-----------------
Just about everything done in this demo is wrong.
There has got to be a far more elegant way of 'converting' c structs
to sql and back. Because basically, that's all tat this code wants
to do: just convert the engine structs to/from corresponding records
in an sql database.
This code only implements writing to the DB, not reading. Its mostly
cut-n-paste code that does the same thing over & over again.
--