Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reading a JSON file into an object #1537

Closed
DragonOsman opened this issue Mar 21, 2019 · 8 comments
Closed

Reading a JSON file into an object #1537

DragonOsman opened this issue Mar 21, 2019 · 8 comments

Comments

@DragonOsman
Copy link

Hi, everyone.

I want to read a JSON object file and store it into an object in my code. I have two such objects that I want to read into.

This is the code I have for this:

// This function queries the currency API for a list of currencies
const json &cache_storage::query_list(const char *currencykey, const json &sentry)
{
	boost::beast::error_code ec;
	std::map<const std::string, std::pair<std::chrono::time_point<std::chrono::steady_clock>, json>>::iterator found;
	try
	{
		// Read latest currency list from the API and current one that we have 
		// from files on disk and store them in json objects. If the latest version is different, make 
		// a new request and cache it, otherwise use the current one we already have 
		// in the existing cache (try to check whether the same currency list is there in the cache)
		// Latest currency list from the API must be kept updated to the latest version at all times
		std::ifstream ifs1{ "currency_list_latest.json" };
		std::ifstream ifs2{ "currency_list_current.json" };
		json latest_data = json::parse(ifs1), current_data = json::parse(ifs2);
		ifs1 >> latest_data;
		ifs2 >> current_data;
		found = m_cache.find(latest_data);
		std::cout << "latest_data: " << latest_data.get<std::string>() << '\n';
		std::cout << "current_data: " << current_data.get<std::string>() << '\n';

		if (found == m_cache.end() || (std::chrono::steady_clock::now() - found->second.first) > m_duration)
		{
			std::string host{ "bankersalgo.com" }, api_endpoint{ "/currencies_names" }, key{ currencykey };
			std::string target = api_endpoint + '/' + key;
			std::string port{ "443" };
			int version = 11;

			// The io_context is required for all IO
			boost::asio::io_context ioc;

			// The SSL context is required, and holds certificates
			ssl::context ctx{ ssl::context::tlsv12_client };
		
			// These objects perform our IO
			tcp::resolver resolver{ ioc };
			ssl::stream<tcp::socket> stream{ ioc, ctx };

			// Set SNI Hostname (many hosts need this to handshake successfully)
			if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str()))
			{
				boost::system::error_code ec{ static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() };
				throw boost::system::system_error{ ec };
			}

			// Look up the domain name
			const auto results = resolver.resolve(host, port);

			// This holds the root certificate used for verification
			load_root_certificates(ctx);

			// Verify the remote server's certificate
			ctx.set_verify_mode(ssl::verify_peer);

			// Make the connection on the IP address we get from a lookup
			boost::asio::connect(stream.next_layer(), results.begin(), results.end());

			// Perform the SSL handshake
			stream.handshake(ssl::stream_base::client, ec);
			if (ec)
			{
				std::cerr << "Lines 850 and 851:\n";
				fail(ec, "handshake");
			}

			// Set up an HTTP GET request message
			http::request<http::string_body> req{ http::verb::get, target, version };
			req.set(http::field::host, host);
			req.set(http::field::content_type, "application/json");
			req.set(http::field::accept, "application/json");
			req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
			std::cout << "Line 860: Request: " << req << '\n';

			// Send the HTTP request to the remote host
			http::write(stream, req);

			// This buffer is used for reading and must be persisted
			boost::beast::flat_buffer buffer;

			// Declare a container to hold the response
			http::response<http::string_body> res;

			// Receive the HTTP response
			http::read(stream, buffer, res);
			std::cout << "Line 873: response: " << res << '\n';
			found = m_cache.insert_or_assign(found, latest_data, std::make_pair(std::chrono::steady_clock::now(), json::parse(res.body())));

			// Gracefully close the stream
			boost::system::error_code ec;
			stream.shutdown(ec);
			if (ec == boost::asio::error::eof)
			{
				// Rationale:
				// http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
				ec.assign(0, ec.category());
			}
			if (ec)
			{
				throw boost::system::system_error{ ec };
			}

			// If we get here then the connection is closed gracefully
		}
		return found->second.second;
	}
	catch (const boost::beast::error_code &ec)
	{
		std::cerr << "Line 896: Error: " << ec.message() << '\n';
	}
	catch (const json::exception &e)
	{
		std::cerr << "Line 900: Error: " << e.what() << '\n';
	}
	catch (const std::exception &e)
	{
		std::cerr << "Line 904: Error: " << e.what() << '\n';
	}
	return sentry;
}

Right now I have a JSON parse exception with the string being "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal". I'd like some help in figuring out why and in fixing this problem.

I'm Windows 10 Home Single Language version 1803 build 17134.648, x64. The compiler is MSVC version 19.16.27027.1 with Visual Studio 2017.

I have the version in the latest branch: version 3.6.1.

I saw a closed issue about this from before, but what I tried is the same as the answer to that issue and it's not working, so I opened a new issue.

@nlohmann
Copy link
Owner

The error message usually means that the file was not opened successfully.

@DragonOsman
Copy link
Author

DragonOsman commented Mar 21, 2019

Thanks for the reply.

I have the files in the same directory as the .cpp file and I'm sure I have the names right. Do I need to give the full filenames, or put them in the same directory as the .exe file?

And it says "parse error". Does this kind of parse error mean that the file wasn't opened successfully, then?

@nlohmann
Copy link
Owner

Oh, another thing: parse already parses the files. Delete the lines

		ifs1 >> latest_data;
		ifs2 >> current_data;

@DragonOsman
Copy link
Author

DragonOsman commented Mar 21, 2019

Okay, thanks. Deleted them.

What about the parsing error, then? Is there a problem with the filename or something?

@nlohmann
Copy link
Owner

Is it still there? To which line does the debugger send you?

@DragonOsman
Copy link
Author

The exception is still there, but my debugger keeps trying to find chkstk.asm which my computer doesn't have so I can't debug it.

I have the files in the same directory as the source code file. Should I give the full path to the files if I keep them there?

@gregmarr
Copy link
Contributor

gregmarr commented Mar 21, 2019

There is no relationship between the source code directory and a file you read from disk at runtime. If you don't use a path, then it's probably trying to read the file from the current directory. That is probably the directory where your binary is located.

The chkstk.asm probably indicates a stack overflow or corruption. Are you using Visual Studio? You can configure it to stop on first change exceptions instead of continuing, and that should give you a better call stack.

@DragonOsman
Copy link
Author

DragonOsman commented Mar 21, 2019

The files are in the same directory as the source code. Putting the path to the file in there helped. But now I have an exception error saying, "[json.exception.type_error.302] type must be string, but is object". What's the nlohmann::json type for a JSON object?

Edit: I decided to put the JSON files in the same directory as the .exe file so that I could use just the filename rather than putting full path to the file along with the name.

Edit2: I have .json files that each have an actual JSON object in them. I need to read that object into a nlohmann::json variable. So how should I do that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants