Read file on server

Twine Version: 2
Story Format: Sugarcube 2

I’m trying to write a custom macro to read a JSON file with initialization information from the server (same place where the generated HTML is place), following advice from greyelf on a very old twine Q&A site: https://twinery.org/forum/discussion/2903/sugarcube-and-variable-from-text

My javascript with some debugging stuff added is:

Macro.add('readJSON', {
	handler : function () {
		var target = this.output,
				storyVar = this.args[0],
				filename = this.args[1];
		if (!storyVar || typeof storyVar !== 'string' || 
				(storyVar[0] !== '$' && storyVar[0] !== '_')) {
			return this.error('Invalid variable name.');
		}
		if (!filename || typeof filename !== 'string') {
			return this.error('Invalid filename to read.');
		}
		// testing:
		State.setVar(storyVar, [filename]);
		$.get(filename,function (data, status) { 
			alert('Status = ' + status);
			State.setVar(storyVar, JSON.parse(data)); 
		}).fail(function( jqXHR, textStatus, errorThrown ) {
			alert('Failure: ' + jqXHR);
			alert('Status: ' + textStatus);
			alert('Error: ' + errorThrown);
        console.log(jqXHR);
        console.log(textStatus);
        console.log(errorThrown );
    });
	}
});

The problem is that whatever I use for the filename (I’ve tried
logins.json
/logins.json
file://logins.json
file:///logins.json
the “fail” lambda gets called with the empty object {} and status “Error” and no other information. Im obviously calling “get” wrong, but don’t know how to fix it.
(BTW: I don’t know if my markup is working – I didn’t see a “preview” button.)

1 Like

I’m not very familiar with $.get, but looking at the jquery docs, it seems like the callback function only takes one argument (data), so I’m not sure what your status variable is doing. I’m not sure if that’s what’s throwing the error.

Theres also this bit regarding the fail method:

If a request with jQuery.get() returns an error code, it will fail silently unless the script has also called the global .ajaxError() method. Alternatively, as of jQuery 1.5, the .error() method of the jqXHR object returned by jQuery.get() is also available for error handling.

Edit:
After researching a bit more, that info is a bit outdated since I guess error() is deprecated by fail(). But the information on fail() doesn’t show that it takes any arguments.

It looks like using ajaxError() really is the correct way to get an error message. Here’s an example taken from the docs page for it.

$( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
  if ( settings.url == "ajax/missing.html" ) {
    $( "div.log" ).text( "Triggered ajaxError handler." );
  }
});

I was using this stack overflow posting to see how to get errors: https://stackoverflow.com/questions/5047906/how-to-detect-jquery-get-failure-seeking-simple-code-example
Having an extra parameter on a callback cannot cause a problem, especially since the success callback is never called.

Yeah, probably not. I was thinking it was like a try/catch kind of thing where it’d fail in the middle, but I think you’re right.

But either way, I was just hoping to help you get an error response that actually held useful information.

1 Like

First, the file:// scheme won’t work at all. You have to use an actual web server and open the game from the server, even if it’s on local machine. Browsers have the security measures that say sites are not allowed to read anything local.

Second, try logins.json or ./logins.json

Also if the server treats json as MIME type application/json jQuery can automatically parse the file when it reads it so no JSON.parse needed. Of course, that depends on jQuery version.

1 Like

OK. It works if I use “logins.json” and use http: as the URL of the twine generated HTML from a web server, but doesn’t work if I use “logins.json” with a file: URL to run the Twine. This means I have to publish the story to a file and then copy it to the web server area, rather than test it from within the Twine tool. I can work with that.
The JSON parsing is still not working but probably just because what @oreolek says about JSON parsing being automatic.

BTW, if you want a workaround that works on local files without needing a local web server running, let me know.

@HiEv: I’m all ears! Especially if it will work BOTH on published twine files AND running from within Twine. But even if not.

Rather than posting a bunch of code here, take a look at the JavaScript section in my Local Storage Manager code (import the HTML into Twine), which is intended to let you export/import a game’s entire SugarCube save slot list. It uses the FileSaver.js code as well.

Just let me know if you have any questions on it.

[EDIT]
P.S. Oh, I forgot that this isn’t mentioned in that code. The output file is written like that so that you can use the importScripts() function to load it, instead of using a dialog box, if you know the path and filename. If you’re unfamiliar with how to use that function, see my “Loading External Scripts” sample code (click “Jump to Start” in the UI bar to see other sample code there).

1 Like