evernote-cloud-sdk-ios
evernote-cloud-sdk-ios copied to clipboard
Evernote IOS SDK fetchResourceByHashWith throws exception
Working with Evernote IOS SDK 3.0 I would like to retrieve a specific resource from note using
fetchResourceByHashWith
This is how I am using it. Just for this example, to be 100% sure about the hash being correct I first download the note with a single resource using fetchNote
and then request this resource using its unique hash using fetchResourceByHashWith
(hash looks correct when I print it)
ENSession.shared.primaryNoteStore()?.fetchNote(withGuid: guid, includingContent: true, resourceOptions: ENResourceFetchOption.includeData, completion: { note, error in
if error != nil {
print(error)
seal.reject(error!)
} else {
let hash = note?.resources[0].data.bodyHash
ENSession.shared.primaryNoteStore()?.fetchResourceByHashWith(guid: guid, contentHash: hash, options: ENResourceFetchOption.includeData, completion: { res, error in
if error != nil {
print(error)
seal.reject(error!)
} else {
print("works")
seal.fulfill(res!)
}})
}
})
Call to fetchResourceByHashWith
fails with
Optional(Error Domain=ENErrorDomain Code=0 "Unknown error" UserInfo={EDAMErrorCode=0, NSLocalizedDescription=Unknown error})
The equivalent setup works on Android SDK. Everything else works so far in IOS SDK (chunkSync, auth, getting notebooks etc.. so this is not an issue with auth tokens)
would be great to know if this is an sdk bug or I am still doing something wrong.
Thanks
SO with bounty https://stackoverflow.com/questions/54668021/evernote-ios-sdk-fetchresourcebyhashwith-throws-exception would love to know if this is a bug or I am still doing something wrong
@AndroidGecko It's a bug. The issue is detailed in an answer to your SO post. Reposting here so someone at Evernote can address it properly:
This is a bug in the SDK's "EDAM" Thrift client stub code. You are invoking the underlying getResourceByHash
API method on the note store, which is defined per the docs to accept a string
type for the contentHash
argument. But it turns out the client is sending the hash value as a binary typed field instead (which is indeed what the text of the documentation suggests should be happening).
If you dig into the more recent Python version of the SDK, you can see a peculiar pattern for this method: it says it's going to write a STRING-type field, and then actually writes a binary one:
if self.contentHash is not None:
oprot.writeFieldBegin('contentHash', TType.STRING, 3)
oprot.writeBinary(self.contentHash)
oprot.writeFieldEnd()
You see a similar pattern in the Android/Java EDAM layer. Weirdly, that pattern works, effectively sending a chimera string/binary type for the contentHash
argument. And if you hack up the iOS SDK to do the same thing, it will work, too.
The bug is either in the Thrift definition/implementation or in the iOS client, but either way the two are mismatched. Marking the field as type string but then actually writing binary data does appear to work correctly, and you can hack up the iOS client to do this if you need to.