We shipped our version 1 iPhone app using version 0.13 of
ObjectiveDDP
to talk to a live Meteor server. When Meteor changed their protocols in 0.8.2,
compatibility with the iPhone app died for us; ironically not because of lack of
backward compatibility, but rather, a
bug in ObjectiveDDP,
which the new Meteor code exposed.
Upgrading ObjectiveDDP versions can solve the problem for
new iOS apps, but what about the ones already out there? The nature of the bug
means that ObjectiveDDP won’t even connect to the server; hence, if we bumped
revisions, we’d have no way to alert the old clients that they’d need to upgrade.
They’d just see endless unavailability.
To solve the problem, we needed to patch the server to have it accept the existing clients. The bug was that the old ObjectiveDDP was
neglecting to inform Meteor of which protocols it could use, so the
fix was to force Meteor to assume the old protocol (‘pre1’) if the
compatibility list wasn’t specified.
Here’s what worked for me...
In ~/.meteor/releases there’s a release.json file corresponding
to each Meteor version. I wanted to get 0.8.2 patched, so took a look inside 0.8.2.release.json.
There, there’s a unique identifier for the version of the livedata component
it’s using. In this case, with the line:
"less":
"188c110be5",
"livedata":
"f9cf0125ce",
"localstorage": "27cc42083e",
Armed with that number, I edited
~/.meteor/packages/livedata/(that number)/os/packages/livedata.js
Somewhere inside, there’s a _handleConnect function. In the case of 0.8.2, it’s around line 1997:
_handleConnect: function (socket, msg) {
var self = this;
// The connect message must specify a version and an array of supported
// versions, and it must claim to support what it is proposing.
if (!(typeof (msg.version) === 'string' &&
_.isArray(msg.support) &&
_.all(msg.support, _.isString) &&
_.contains(msg.support, msg.version))) {
socket.send(stringifyDDP({msg: 'failed',
version: SUPPORTED_DDP_VERSIONS[0]}));
socket.close();
return;
}
...
(Note that I’m omitting to show the numbered comments on the
right hand side of each line. Safest to leave them there and patch around them, I
found).
That empty line after the self declaration was a perfect
opportunity to sneak this in:
var self = this;
if (!msg.support) msg.support = ['pre1'];
// The connect message must specify a version and an array of supported
...
And… world saved for now, but it’s a shame this was
necessary. With more foresight I should have had the old iOS app connect to a
unique hostname, one that resolves to the same IP address as the website,
knowing that I can always shuffle DNS entries around to accommodate any future protocol
divergences.