From a23506c88a3538fbd077e33ae445dc6d35c744fa Mon Sep 17 00:00:00 2001 From: John Ralls Date: Thu, 19 Sep 2024 13:00:33 -0700 Subject: [PATCH 1/2] Add YH Finance (FINANCEAPI) API Key to Quotes infrastructure. And add financeapi to known sources. --- ...uCash.general.finance-quote.gschema.xml.in | 7 +- gnucash/gtkbuilder/dialog-preferences.glade | 30 +++++++- libgnucash/app-utils/gnc-quotes.cpp | 73 +++++++++++-------- libgnucash/engine/gnc-commodity.cpp | 1 + 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/gnucash/gschemas/org.gnucash.GnuCash.general.finance-quote.gschema.xml.in b/gnucash/gschemas/org.gnucash.GnuCash.general.finance-quote.gschema.xml.in index 2248bc3d079..402f4bf261a 100644 --- a/gnucash/gschemas/org.gnucash.GnuCash.general.finance-quote.gschema.xml.in +++ b/gnucash/gschemas/org.gnucash.GnuCash.general.finance-quote.gschema.xml.in @@ -3,7 +3,12 @@ '' Alpha Vantage API key - To retrieve online quotes from Alphavantage, this key needs to be set. A key can be retrieved from the Alpha Vantage website. + Alpha Vantage requires an API key to use their service. You can obtain a key by registering for a free account at the Alpha Vantage website, https://alphavantage.co/support/#api-key. + + + '' + YH Finance (FinanceAPI) API key + YH Finance requires an API key to use their FinanceAPI service. You can obtain a key by registering for a free account at the YH Finance website, https://financeapi.net/pricing. diff --git a/gnucash/gtkbuilder/dialog-preferences.glade b/gnucash/gtkbuilder/dialog-preferences.glade index 66004574108..08f8fb2c854 100644 --- a/gnucash/gtkbuilder/dialog-preferences.glade +++ b/gnucash/gtkbuilder/dialog-preferences.glade @@ -3656,10 +3656,10 @@ many months before the current month 3 6 - + True False - To retrieve online quotes from Alphavantage, this key needs to be set. A key can be retrieved from the Alpha Vantage website. + Alpha Vantage requires an API key to use their service. You can obtain a key by registering for a free account at the Alpha Vantage website, https://www.alphavantage.co/support/#api-key. Alpha Vantage API key @@ -3671,7 +3671,7 @@ many months before the current month True True - To retrieve online quotes from Alphavantage, this key needs to be set. A key can be retrieved from the Alpha Vantage website. + Alpha Vantage requires an API key to use their service. You can obtain a key by registering for a free account at the Alpha Vantage website, https://alphavantage.co/support/#api-key. True @@ -3679,6 +3679,30 @@ many months before the current month 1 + + + True + False + YH Finance requires an API key to use their FinanceAPI service. You can obtain a key by registering for a free account at the YH Finance website, https://financeapi.net/pricing. + YH Finance (FinanceAPI) API key + + + 0 + 2 + + + + + True + True + YH Finance requires an API key to use their FinanceAPI service. You can obtain a key by registering for a free account at the YH Finance website, https://financeapi.net/pricing. + True + + + 1 + 2 + + True diff --git a/libgnucash/app-utils/gnc-quotes.cpp b/libgnucash/app-utils/gnc-quotes.cpp index 50d4eaac7ed..83c4ab785ad 100644 --- a/libgnucash/app-utils/gnc-quotes.cpp +++ b/libgnucash/app-utils/gnc-quotes.cpp @@ -20,6 +20,7 @@ * Boston, MA 02110-1301, USA gnu@gnu.org * \ *******************************************************************/ +#include #include #include @@ -61,6 +62,8 @@ #include static const QofLogModule log_module = "gnc.price-quotes"; +static const char* av_api_env = "ALPHAVANTAGE_API_KEY"; +static const char* yh_api_env = "FINANCEAPI_API_KEY"; namespace bl = boost::locale; namespace bp = boost::process; @@ -128,7 +131,8 @@ class GncFQQuoteSource final : public GncQuoteSource std::string c_fq_wrapper; std::string m_version; StrVec m_sources; - std::string m_api_key; + std::string m_av_api_key; + std::string m_yh_api_key; public: GncFQQuoteSource(); ~GncFQQuoteSource() = default; @@ -146,9 +150,28 @@ static std::string parse_quotesource_error(const std::string& line); static const std::string empty_string{}; +static inline std::string +get_api_key(const char* prefskey, const char* envvar) +{ + std::string keyval{}; + auto key = gnc_prefs_get_string ("general.finance-quote", prefskey); + if (!(key && *key)) + { + g_free (key); + key = g_strdup(getenv(envvar)); + } + + if (key) + { + keyval = std::string(key); + g_free (key); + } + return keyval; +} + GncFQQuoteSource::GncFQQuoteSource() : c_cmd{bp::search_path("perl")}, -m_version{}, m_sources{}, m_api_key{} +m_version{}, m_sources{}, m_av_api_key{}, m_yh_api_key{} { char *bindir = gnc_path_get_bindir(); c_fq_wrapper = std::string(bindir) + "/finance-quote-wrapper"; @@ -180,20 +203,10 @@ m_version{}, m_sources{}, m_api_key{} m_sources = std::move(sources); std::sort (m_sources.begin(), m_sources.end()); - auto av_key = gnc_prefs_get_string ("general.finance-quote", "alphavantage-api-key"); - if (!(av_key && *av_key)) - { - g_free (av_key); - av_key = g_strdup(getenv("ALPHAVANTAGE_API_KEY")); - } - - if (av_key) - { - m_api_key = std::string(av_key); - g_free (av_key); - } - else + m_av_api_key = get_api_key("alphavantage-api-key", av_api_env); + if (m_av_api_key.empty()) PWARN("No Alpha Vantage API key set, currency quotes and other AlphaVantage based quotes won't work."); + m_yh_api_key = get_api_key("yhfinance-api-key", yh_api_env); } QuoteResult @@ -215,26 +228,22 @@ GncFQQuoteSource::run_cmd (const StrVec& args, const std::string& json_string) c boost::asio::io_service svc; auto input_buf = bp::buffer (json_string); + auto curr_env{boost::this_process::environment()}; + bp::environment new_env{curr_env}; bp::child process; - if (m_api_key.empty()) - process = bp::child(c_cmd, args, - bp::std_out > out_buf, - bp::std_err > err_buf, - bp::std_in < input_buf, -#ifdef BOOST_WINDOWS_API - bp::windows::create_no_window, -#endif - svc); - else - process = bp::child(c_cmd, args, - bp::std_out > out_buf, - bp::std_err > err_buf, - bp::std_in < input_buf, + if (!m_av_api_key.empty()) + new_env[av_api_env] = m_av_api_key; + if (!m_yh_api_key.empty()) + new_env[yh_api_env] = m_yh_api_key; + process = bp::child(c_cmd, args, + bp::std_out > out_buf, + bp::std_err > err_buf, + bp::std_in < input_buf, #ifdef BOOST_WINDOWS_API - bp::windows::create_no_window, + bp::windows::create_no_window, #endif - bp::env["ALPHAVANTAGE_API_KEY"] = m_api_key, - svc); + new_env, + svc); svc.run(); process.wait(); diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp index caaeea8c0a4..f6bd0155b92 100644 --- a/libgnucash/engine/gnc-commodity.cpp +++ b/libgnucash/engine/gnc-commodity.cpp @@ -217,6 +217,7 @@ static QuoteSourceList single_quote_sources = { false, SOURCE_SINGLE, "US Govt. Thrift Savings Plan", "tsp" }, { false, SOURCE_SINGLE, "Yahoo as JSON", "yahoo_json" }, { false, SOURCE_SINGLE, "Yahoo Web", "yahooweb" }, + { false, SOURCE_SINGLE, "YH Finance (FinanceAPI)", "financeapi" }, }; static QuoteSourceList multiple_quote_sources = From 9c9ad7c271c88ab0585f0442f985cf451e5ff5ed Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 20 Sep 2024 14:55:41 -0700 Subject: [PATCH 2/2] Replace GncFQQuoteSource api-key members with a bp::environment one. --- libgnucash/app-utils/gnc-quotes.cpp | 64 ++++++++++++----------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/libgnucash/app-utils/gnc-quotes.cpp b/libgnucash/app-utils/gnc-quotes.cpp index 83c4ab785ad..e86c76e6905 100644 --- a/libgnucash/app-utils/gnc-quotes.cpp +++ b/libgnucash/app-utils/gnc-quotes.cpp @@ -63,7 +63,9 @@ static const QofLogModule log_module = "gnc.price-quotes"; static const char* av_api_env = "ALPHAVANTAGE_API_KEY"; +static const char* av_api_key = "alphavantage-api-key"; static const char* yh_api_env = "FINANCEAPI_API_KEY"; +static const char* yh_api_key = "yhfinance-api-key"; namespace bl = boost::locale; namespace bp = boost::process; @@ -131,8 +133,7 @@ class GncFQQuoteSource final : public GncQuoteSource std::string c_fq_wrapper; std::string m_version; StrVec m_sources; - std::string m_av_api_key; - std::string m_yh_api_key; + bp::environment m_env; public: GncFQQuoteSource(); ~GncFQQuoteSource() = default; @@ -141,7 +142,7 @@ class GncFQQuoteSource final : public GncQuoteSource QuoteResult get_quotes(const std::string&) const override; private: QuoteResult run_cmd (const StrVec& args, const std::string& json_string) const; - + void set_api_key(const char* api_pref, const char* api_env); }; static void show_quotes(const bpt::ptree& pt, const StrVec& commodities, bool verbose); @@ -150,28 +151,9 @@ static std::string parse_quotesource_error(const std::string& line); static const std::string empty_string{}; -static inline std::string -get_api_key(const char* prefskey, const char* envvar) -{ - std::string keyval{}; - auto key = gnc_prefs_get_string ("general.finance-quote", prefskey); - if (!(key && *key)) - { - g_free (key); - key = g_strdup(getenv(envvar)); - } - - if (key) - { - keyval = std::string(key); - g_free (key); - } - return keyval; -} - GncFQQuoteSource::GncFQQuoteSource() : c_cmd{bp::search_path("perl")}, -m_version{}, m_sources{}, m_av_api_key{}, m_yh_api_key{} +m_version{}, m_sources{}, m_env{boost::this_process::environment()} { char *bindir = gnc_path_get_bindir(); c_fq_wrapper = std::string(bindir) + "/finance-quote-wrapper"; @@ -203,10 +185,8 @@ m_version{}, m_sources{}, m_av_api_key{}, m_yh_api_key{} m_sources = std::move(sources); std::sort (m_sources.begin(), m_sources.end()); - m_av_api_key = get_api_key("alphavantage-api-key", av_api_env); - if (m_av_api_key.empty()) - PWARN("No Alpha Vantage API key set, currency quotes and other AlphaVantage based quotes won't work."); - m_yh_api_key = get_api_key("yhfinance-api-key", yh_api_env); + set_api_key(av_api_key, av_api_env); + set_api_key(yh_api_key, yh_api_env); } QuoteResult @@ -228,13 +208,7 @@ GncFQQuoteSource::run_cmd (const StrVec& args, const std::string& json_string) c boost::asio::io_service svc; auto input_buf = bp::buffer (json_string); - auto curr_env{boost::this_process::environment()}; - bp::environment new_env{curr_env}; bp::child process; - if (!m_av_api_key.empty()) - new_env[av_api_env] = m_av_api_key; - if (!m_yh_api_key.empty()) - new_env[yh_api_env] = m_yh_api_key; process = bp::child(c_cmd, args, bp::std_out > out_buf, bp::std_err > err_buf, @@ -242,7 +216,7 @@ GncFQQuoteSource::run_cmd (const StrVec& args, const std::string& json_string) c #ifdef BOOST_WINDOWS_API bp::windows::create_no_window, #endif - new_env, + m_env, svc); svc.run(); @@ -281,6 +255,24 @@ GncFQQuoteSource::run_cmd (const StrVec& args, const std::string& json_string) c return QuoteResult (cmd_result, std::move(out_vec), std::move(err_vec)); } +void +GncFQQuoteSource::set_api_key(const char* api_key, const char* api_env) +{ + auto key = gnc_prefs_get_string("general.finance-quote", api_key); + if (key && *key) + { + m_env[api_env] = key; + g_free(key); + } + else + { + if (api_key == av_api_key && m_env.find(api_env) == m_env.end()) + PWARN("No Alpha Vantage API key set, currency quotes and other " + "AlphaVantage based quotes won't work."); + g_free(key); + } +} + /* GncQuotes implementation */ GncQuotesImpl::GncQuotesImpl() : m_quotesource{new GncFQQuoteSource}, m_sources{}, m_failures{}, @@ -1040,9 +1032,7 @@ GncQuotes::GncQuotes () try { m_impl = std::make_unique(); - } - catch (const GncQuoteSourceError& err) - { + } catch (const GncQuoteSourceError &err) { throw(GncQuoteException(err.what())); } }