Skip to content

Commit

Permalink
Finish initial implementation of building quote source lists from F::…
Browse files Browse the repository at this point in the history
…Q at startup instead of hard-coding quote sources
  • Loading branch information
vincentl committed Jul 22, 2023
1 parent 03b777a commit 5e8d7e1
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 54 deletions.
2 changes: 1 addition & 1 deletion gnucash/gnome-utils/dialog-commodity.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ gnc_ui_source_menu_create(QuoteSourceType type)
source = gnc_quote_source_lookup_by_ti(type, i);
if (source == NULL)
break;
name = gnc_quote_source_get_user_name(source);
name = gnc_quote_source_get_name(source);
supported = gnc_quote_source_get_supported(source);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
Expand Down
2 changes: 1 addition & 1 deletion gnucash/gnome-utils/gnc-tree-model-commodity.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ gnc_tree_model_commodity_get_value (GtkTreeModel *tree_model,
if (gnc_commodity_get_quote_flag (commodity))
{
source = gnc_commodity_get_quote_source (commodity);
g_value_set_string (value, gnc_quote_source_get_internal_name(source));
g_value_set_string (value, gnc_quote_source_get_name(source));
}
else
{
Expand Down
30 changes: 20 additions & 10 deletions gnucash/gnucash-commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,20 @@ Gnucash::check_finance_quote (void)
std::cout << bl::translate ("Finance::Quote sources:\n");
int count{0};
const auto width{12};
for (auto source : quotes.sources())
const QuoteSources source_type[] = {quotes.single_sources(), quotes.multiple_sources()};
for (auto source_list : source_type)
{
auto mul{source.length() / width + 1};
count += mul;
if (count > 6)
for (auto source : source_list)
{
count = mul;
std::cout << "\n";
auto mul{source.length() / width + 1};
count += mul;
if (count > 6)
{
count = mul;
std::cout << "\n";
}
std::cout << std::setw(mul * (width + 1)) << std::left << source;
}
std::cout << std::setw(mul * (width + 1)) << std::left << source;
}
std::cout << std::endl;
return 0;
Expand Down Expand Up @@ -353,9 +357,15 @@ Gnucash::add_quotes (const bo_str& uri)
{
GncQuotes quotes;
std::cout << bl::format (bl::translate ("Found Finance::Quote version {1}.")) % quotes.version() << std::endl;
auto quote_sources = quotes.sources_as_glist();
gnc_quote_source_set_fq_installed (quotes.version().c_str(), quote_sources);
g_list_free_full (quote_sources, g_free);

auto currency_quote_sources = quotes.currency_sources_as_glist();
auto single_quote_sources = quotes.single_sources_as_glist();
auto multiple_quote_sources = quotes.multiple_sources_as_glist();
gnc_quote_source_set_fq_installed (quotes.version().c_str(), currency_quote_sources, single_quote_sources, multiple_quote_sources);
g_list_free_full (currency_quote_sources, g_free);
g_list_free_full (single_quote_sources, g_free);
g_list_free_full (multiple_quote_sources, g_free);

quotes.fetch(qof_session_get_book(session));
if (quotes.had_failures())
std::cerr << quotes.report_failures() << std::endl;
Expand Down
10 changes: 7 additions & 3 deletions gnucash/gnucash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,13 @@ scm_run_gnucash (void *data, [[maybe_unused]] int argc, [[maybe_unused]] char **
gnc_update_splash_screen (checking, GNC_SPLASH_PERCENTAGE_UNKNOWN);
GncQuotes quotes;
auto found = (bl::format (std::string{_("Found Finance::Quote version {1}.")}) % quotes.version()).str();
auto quote_sources = quotes.sources_as_glist();
gnc_quote_source_set_fq_installed (quotes.version().c_str(), quote_sources);
g_list_free_full (quote_sources, g_free);
auto currency_quote_sources = quotes.currency_sources_as_glist();
auto single_quote_sources = quotes.single_sources_as_glist();
auto multiple_quote_sources = quotes.multiple_sources_as_glist();
gnc_quote_source_set_fq_installed (quotes.version().c_str(), currency_quote_sources, single_quote_sources, multiple_quote_sources);
g_list_free_full (currency_quote_sources, g_free);
g_list_free_full (single_quote_sources, g_free);
g_list_free_full (multiple_quote_sources, g_free);
gnc_update_splash_screen (found.c_str(), GNC_SPLASH_PERCENTAGE_UNKNOWN);
}
catch (const GncQuoteException& err)
Expand Down
19 changes: 9 additions & 10 deletions libgnucash/app-utils/gnc-quotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,26 +229,25 @@ m_version{}, m_currency_sources{}, m_single_sources{}, m_multiple_sources{}, m_a
// info["quote_methods"] = { "name" : ["module_name", ...] }
// info["quote_modules"] = { "name" : ["feature_name", ...] }
//
// A quote_method is the name for one more quote sources, such as NYSE
// A quote_module is a single source with option "features"
// A quote_method is the name for one or more quote sources, such as nasdaq (multiple) or alphavantage (single)
// A quote_module is backs one or more methods and may have required features.
// A "feature_name" is something like "API_KEY", a need value for the source

PWARN("TAG: %s", info["currency_modules"]["AlphaVantage"][0].c_str());
m_version = std::move(version);

for (auto& it : info["currency_modules"]) {
m_currency_sources.push_back(it.first);
}
std::sort (m_currency_sources.begin(), m_currency_sources.end());

for (auto& it : info["quote_modules"]) {
m_single_sources.push_back(it.first);
}
std::sort (m_single_sources.begin(), m_single_sources.end());

for (auto& it : info["quote_methods"]) {
m_multiple_sources.push_back(it.first);
// Sort methods into single vs multiple sources
if (info["quote_methods"][it.first].size() == 1)
m_single_sources.push_back(it.first);
else
m_multiple_sources.push_back(it.first);
}
std::sort (m_single_sources.begin(), m_single_sources.end());
std::sort (m_multiple_sources.begin(), m_multiple_sources.end());
}
catch (std::exception &e)
Expand Down Expand Up @@ -546,7 +545,7 @@ GncQuotesImpl::comm_vec_to_json_string(const CommVec &comm_vec) const
return;
}
else
comm_ns = gnc_quote_source_get_internal_name(gnc_commodity_get_quote_source(comm));
comm_ns = gnc_quote_source_get_name(gnc_commodity_get_quote_source(comm));

pt.put (make_quote_path(comm_ns, comm_mnemonic), "");
}
Expand Down
12 changes: 8 additions & 4 deletions libgnucash/app-utils/gnc-quotes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,14 @@ class GncQuotes
*/
GList* currency_sources_as_glist ();

/** Get quote sources that use a single upstream source as a std::vector. Finance::Quote
* has "modules" (which gather quotes from a single upstream source) and "methods" (which
* use a combination of modules to retrieve quotes, trying one and then
* falling back to other modules if the first fails.
/** Get quote sources that use a single upstream source as a std::vector.
* Finance::Quote has "modules" that gather quotes from a single upstream
* source and "methods" that use one or more modules to retrieve quotes
* (trying one and then falling back to other modules if the first fails).
*
* A module typically provides a method with the same name (eg the AlphaVantage
* module provides the alphavantage method as well as being one of the sources
* for the nasdaq method).
*
* @return The single sources configured in Finance::Quote
*/
Expand Down
75 changes: 58 additions & 17 deletions libgnucash/engine/gnc-commodity.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,21 @@ struct gnc_quote_source_s
char *name;
};

/**
* Finanace::Quote supports multiple sources for currency information, but they are
* not exposed as separate methods. The F::Q object must be constructed with currency
* sources listed in order of preference (or through an envionment variable). currently,
* GNC uses "currency" as the source internally and the F::Q wrapper uses that source
* name as the indicator to call the F::Q->currency function.
*
* Here, currency_quote_sources is a 1-long list for the "currency" source.
* fq_currency_quote_sources stores the list of available currency sources assigned
* as reported by F::Q and can be used in the future to enable more user control of the
* currency source.
**/

static GList *currency_quote_sources = NULL;
static GList *fq_currency_quote_sources = NULL;
static GList *single_quote_sources = NULL;
static GList *multiple_quote_sources = NULL;
static GList *unknown_quote_sources = NULL;
Expand All @@ -172,7 +186,6 @@ gnc_quote_source_fq_installed (void)
return (fq_version != NULL);
}


/********************************************************************
* gnc_quote_source_fq_version
*
Expand All @@ -194,6 +207,7 @@ gint gnc_quote_source_num_entries(QuoteSourceType type)
{
switch (type) {
case SOURCE_CURRENCY: return g_list_length(currency_quote_sources); break;
case SOURCE_FQ_CURRENCY: return g_list_length(fq_currency_quote_sources); break;
case SOURCE_SINGLE: return g_list_length(single_quote_sources); break;
case SOURCE_MULTI: return g_list_length(multiple_quote_sources); break;
case SOURCE_UNKNOWN: return g_list_length(unknown_quote_sources); break;
Expand Down Expand Up @@ -223,6 +237,10 @@ gnc_quote_source_add_new (const char *source_name, QuoteSourceType type)
new_source->index = g_list_length(currency_quote_sources);
currency_quote_sources = g_list_append(currency_quote_sources, new_source);
break;
case SOURCE_FQ_CURRENCY:
new_source->index = g_list_length(fq_currency_quote_sources);
fq_currency_quote_sources = g_list_append(fq_currency_quote_sources, new_source);
break;
case SOURCE_SINGLE:
new_source->index = g_list_length(single_quote_sources);
single_quote_sources = g_list_append(single_quote_sources, new_source);
Expand Down Expand Up @@ -256,6 +274,7 @@ gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
switch (type)
{
case SOURCE_CURRENCY: source_list = currency_quote_sources; break;
case SOURCE_FQ_CURRENCY: source_list = fq_currency_quote_sources; break;
case SOURCE_SINGLE: source_list = single_quote_sources; break;
case SOURCE_MULTI: source_list = multiple_quote_sources; break;
case SOURCE_UNKNOWN: source_list = unknown_quote_sources; break;
Expand All @@ -275,7 +294,7 @@ gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
}

gnc_quote_source *
gnc_quote_source_lookup_by_name(const char * name, QuoteSourceType type)
gnc_quote_source_lookup_by_name_and_type(const char * name, QuoteSourceType type)
{
if ((name == NULL) || (g_strcmp0(name, "") == 0))
{
Expand All @@ -285,12 +304,13 @@ gnc_quote_source_lookup_by_name(const char * name, QuoteSourceType type)
GList *source_list = NULL;
switch (type) {
case SOURCE_CURRENCY: source_list = currency_quote_sources; break;
case SOURCE_FQ_CURRENCY: source_list = fq_currency_quote_sources; break;
case SOURCE_SINGLE: source_list = single_quote_sources; break;
case SOURCE_MULTI: source_list = multiple_quote_sources; break;
case SOURCE_UNKNOWN: source_list = unknown_quote_sources; break;
}

for (GList* node = sources_list; node; node = node->next) {
for (GList* node = source_list; node; node = node->next) {
gnc_quote_source *source = node->data;

if (g_strcmp0(name, source->name) == 0)
Expand All @@ -301,6 +321,25 @@ gnc_quote_source_lookup_by_name(const char * name, QuoteSourceType type)
return NULL;
}

gnc_quote_source *
gnc_quote_source_lookup_by_name(const char * name)
{
// "currency" is the internal GNC name that causes the F::Q wrapper to call the currency conversion routine
if (g_strcmp0(name, "currency") == 0)
return gnc_quote_source_lookup_by_name_and_type(name, SOURCE_CURRENCY);

// Otherwise, the source must be in one of the following since SOURCE_FQ_CURRENCY is not currently in use
gnc_quote_source *source = NULL;
if (NULL != (source = gnc_quote_source_lookup_by_name_and_type(name, SOURCE_SINGLE)))
return source;
if (NULL != (source = gnc_quote_source_lookup_by_name_and_type(name, SOURCE_MULTI)))
return source;
if (NULL != (source = gnc_quote_source_lookup_by_name_and_type(name, SOURCE_UNKNOWN)))
return source;

return NULL;
}

/********************************************************************
* gnc_quote_source_get_xxx
*
Expand Down Expand Up @@ -382,11 +421,15 @@ void gnc_quote_source_set_fq_installed (const char* version_string,
if (version_string)
fq_version = g_strdup (version_string);

for (node = currency_quote_sources; node; node = node->next)
gnc_quote_source_add_new(node->data, SOURCE_CURRENCY);
for (node = single_quote_sources; node; node = node->next)
// Register GNC "currency" first
gnc_quote_source_add_new("currency", SOURCE_CURRENCY);

// Now register all the info reported by F::Q
for (node = currency_sources_list; node; node = node->next)
gnc_quote_source_add_new(node->data, SOURCE_FQ_CURRENCY);
for (node = single_sources_list; node; node = node->next)
gnc_quote_source_add_new(node->data, SOURCE_SINGLE);
for (node = multiple_quote_sources; node; node = node->next)
for (node = multiple_sources_list; node; node = node->next)
gnc_quote_source_add_new(node->data, SOURCE_MULTI);
}

Expand Down Expand Up @@ -702,7 +745,7 @@ gnc_commodity_new(QofBook *book, const char * fullname,
if (gnc_commodity_namespace_is_iso(name_space))
{
gnc_commodity_set_quote_source(retval,
gnc_quote_source_lookup_by_name("alphavantage", SOURCE_CURRENCY) );
gnc_quote_source_lookup_by_name_and_type("currency", SOURCE_CURRENCY) );
}
}
gnc_commodity_set_fullname(retval, fullname);
Expand Down Expand Up @@ -956,17 +999,17 @@ gnc_commodity_get_quote_source(const gnc_commodity *cm)
if (!cm) return NULL;
priv = GET_PRIVATE(cm);
if (!priv->quote_source && gnc_commodity_is_iso(cm))
return &currency_quote_source;
return gnc_quote_source_lookup_by_name_and_type("currency", SOURCE_CURRENCY);
return priv->quote_source;
}

gnc_quote_source*
gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
{
if (cm && gnc_commodity_is_iso(cm))
return &currency_quote_source;
return gnc_quote_source_lookup_by_name_and_type("currency", SOURCE_CURRENCY);
/* Should make this a user option at some point. */
return gnc_quote_source_lookup_by_name("alphavantage", SOURCE_SINGLE);
return gnc_quote_source_lookup_by_name_and_type("alphavantage", SOURCE_SINGLE);
}

/********************************************************************
Expand Down Expand Up @@ -1077,7 +1120,7 @@ gnc_commodity_set_namespace(gnc_commodity * cm, const char * name_space)
gnc_commodity_begin_edit(cm);
priv->name_space = nsp;
if (nsp->iso4217)
priv->quote_source = gnc_quote_source_lookup_by_internal("currency");
priv->quote_source = gnc_quote_source_lookup_by_name_and_type("currency", SOURCE_CURRENCY);
mark_commodity_dirty(cm);
reset_printname(priv);
reset_unique_name(priv);
Expand Down Expand Up @@ -1233,7 +1276,7 @@ gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
void
gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
{
ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->internal_name : "unknown");
ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->name : "unknown");

if (!cm) return;
gnc_commodity_begin_edit(cm);
Expand Down Expand Up @@ -1962,7 +2005,7 @@ get_quotables_helper1(gpointer key, gpointer value, gpointer data)
GList ** l = data;

if (!priv->quote_flag ||
!priv->quote_source || !priv->quote_source->supported)
!priv->quote_source || priv->quote_source->type != SOURCE_UNKNOWN)
return;
*l = g_list_prepend(*l, value);
}
Expand All @@ -1974,7 +2017,7 @@ get_quotables_helper2 (gnc_commodity *comm, gpointer data)
gnc_commodityPrivate* priv = GET_PRIVATE(comm);

if (!priv->quote_flag ||
!priv->quote_source || !priv->quote_source->supported)
!priv->quote_source || priv->quote_source->type != SOURCE_UNKNOWN)
return TRUE;
*l = g_list_prepend(*l, comm);
return TRUE;
Expand Down Expand Up @@ -2343,8 +2386,6 @@ static QofObject commodity_table_object_def =
gboolean
gnc_commodity_table_register (void)
{
gnc_quote_source_init_tables();

if (!qof_object_register (&commodity_object_def))
return FALSE;
if (!qof_object_register (&namespace_object_def))
Expand Down
29 changes: 21 additions & 8 deletions libgnucash/engine/gnc-commodity.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,11 @@ typedef enum
SOURCE_MULTI, /**< This quote source may pull from multiple
* web sites. For example, the australia
* source may pull from ASX, yahoo, etc. */
SOURCE_UNKNOWN, /**< This is a locally installed quote source
* that gnucash knows nothing about. May
* pull from single or multiple
* locations. */
SOURCE_UNKNOWN, /**< This is a quote source observed in user's data
* file but not known to F::Q. */
SOURCE_FQ_CURRENCY, /**< An F::Q currency source. */
SOURCE_MAX,
SOURCE_CURRENCY = SOURCE_MAX, /**< The special currency quote source. */
SOURCE_CURRENCY = SOURCE_MAX, /**< The special currency quote source called "currency". */
} QuoteSourceType;

/** This function indicates whether or not the Finance::Quote module
Expand Down Expand Up @@ -191,8 +190,8 @@ gint gnc_quote_source_num_entries(QuoteSourceType type);
*/
gnc_quote_source *gnc_quote_source_add_new(const char * name, QuoteSourceType type);

/** Given the F::Q name of a quote source, find
* the data structure identified by this name.
/** Given the F::Q name of a quote source and the type, find
* the corresponding data structure.
*
* @param name The name of this quote source
* @param type The type of the quote source
Expand All @@ -201,7 +200,21 @@ gnc_quote_source *gnc_quote_source_add_new(const char * name, QuoteSourceType ty
* internal name.
*/
/*@ dependent @*/
gnc_quote_source *gnc_quote_source_lookup_by_name(const char * name, QuoteSourceType type);

gnc_quote_source *gnc_quote_source_lookup_by_name_and_type(const char * name, QuoteSourceType type);

/** Given the F::Q name of a quote source, find
* the data structure identified by this name. The name "currency"
* is a special case, referring to the internal name for calling
* F::Q currency conversion.
*
* @param name The name of this quote source
*
* @return A pointer to the price quote source that has the specified
* internal name.
*/
/*@ dependent @*/
gnc_quote_source *gnc_quote_source_lookup_by_name(const char * name);

/** Given the type/index of a quote source, find the data structure
* identified by this pair.
Expand Down

0 comments on commit 5e8d7e1

Please sign in to comment.