I have a google drive app which will auto-save changes. If you have two active sessions then they will overwrite each other. The app supports merging changes but I can't see how to safely integrate this with the drive API. Some options I have considered:
Version safe commits
Use google drive to "only update if current revision in drive == X otherwise fail"
If failed then fetch latest version, merge and retry
problem: I don't think drive supports this. Previous API versions used etags but I see no mention of this in the current documenation.
Pre-commit check
check current saved version, if still current, save
otherwise download, merge and update
problem: obvious race condition between clients
Post-commit check
save new version
if new version is as expected: done
if new version higher than expected: download previous version, merge and update
problem: I don't have much faith this is safe. I can see multiple clients getting in edit loops.
Google real-time api - field binding
replace file format with a google rt datamodel
problem: It would require redesigning just for google-rt
Google real-time api - document support
use google rt api external document support
problem: I don't think this solves the problem
I would really like a way to achieve #1 but any suggestions would be helpful. I would be happy enough with a basic locking / handover scheme between clients but I don't think Drive supports that either.
According to here, "If-Match" using etags still works. Not sure if it applies to data, but at least it applies to metadata.
To follow up on user1828559's answer, the following Java code seems to work well:
private File updateDriveFile(Drive drive, File file, byte[] data) throws IOException {
try {
ByteArrayContent mediaContent = new ByteArrayContent(MIME_TYPE, data);
Drive.Files.Update update = drive.files().update(file.getId(), file, mediaContent);
update.getRequestHeaders().setIfMatch(file.getEtag());
return update.execute();
}
catch (GoogleJsonResponseException e) {
if (isConflictError(e.getDetails())) {
logger.warn("ETag precondition failed, concurrent modification detected!");
return null;
}
throw e;
}
}
private boolean isConflictError(GoogleJsonError error) {
if (error.getCode() == 412) {
final List<GoogleJsonError.ErrorInfo> errors = error.getErrors();
if (errors != null && errors.size() == 1) {
final GoogleJsonError.ErrorInfo errorInfo = errors.get(0);
if ("header".equals(errorInfo.getLocationType()) &&
"If-Match".equals(errorInfo.getLocation()) &&
"conditionNotMet".equals(errorInfo.getReason()))
return true;
}
}
return false;
}
Related
I want my data access layer to handle exceptions thrown by DocumentDB API provided via Microsoft.Azure.Documents.Client.DocumentClient class. For example, the optimistic concurrency check implemented using AccessCondition class, but others as well.
By looking at the exception thrown, the best way to recognize different DocumentClient-specific exceptions seems to be something like this:
try { ... }
catch (DocumentClientException exception)
when (exception.Error.Code == "Some magic here")
{
//let the user know how to recover from this..
}
I don't like such magic strings as they are not verifiable compile-time. It may contract a typo, or it may change on random moment with DocumentDB client/server changes, etc. Also, it is not clear which such magic codes I could/should be handling since I don't see the Microsoft.Azure.DocumentDB .net API containing any ErrorCodes enum or constants, nor find any list in documentation.
Where can I find a list of possible Error.Code values DocumentClient API can throw?
To make it even more confusing, the XmlDoc for DocumentClient.CreateDocumentAsync method suggest working instead on http status codes.
UPDATE: This question is not about Http status codes but DocumentClientException.Error.Code field as I assume the latter is more precise.
Where can I find a list of possible error codes values DocumentClient API can throw?
It's hard to find the completely list of error code that DocumentClinet API throw. The exception is depend on what your request.
For example, the optimistic concurrency check
Azure Cosmos DB uses ETags for handling optimistic concurrency.
When we retrieve a document from Azure Cosmos DB, it always contains an ETag property as apart of our document.
When we then want to send our request to replace a document, we can specify an AccessCondition with the ETag we received when we fetched out our document.
If the ETag we send is not current, the server will return a 412 Precondition Failed status code. In our .NET SDK, this is wrapped up in a DocumentClientException.
Here is an example that show the possible problems when the concurrency occurred.
By decompile the version 1.22.0 client, the code is set as a HttpStatusCode enum. I think all the possible values can be found here https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx then.
However, what really contains richer information for debug is the Error.Message. Might need to decompile the whole library to figure out, or wait for Microsoft to release the source codes, which is unlikely to happen since the latest update in github was 2 or 3 years ago.
public Error Error
{
get
{
if (this.error == null)
{
this.error = new Error()
{
Code = this.StatusCode.ToString(),
Message = this.Message
};
}
return this.error;
}
}
There is a list of the HTTP Status Codes for Azure Cosmos DB
I use the following code in my catch blocks
catch (DocumentClientException e)
{
var resp = new HttpResponseMessage
{
StatusCode = (HttpStatusCode) e.StatusCode,
Content = new StringContent(e.Message)
};
return resp;
}
Letting the user know how to handle the exception should be done on the client application.
I’m using Xamarin Forms to do some cross platform applications and I’d like to offer DropBox and GoogleDrive as places where users can do backups, cross platform data sharing and the like. I was able to get DropBox working without doing platform specific shenanagins just fine, but Google Drive is really giving me fits. I have my app setup properly with Google and have tested it with a regular CLI .NET application using their examples that read the JSON file off the drive and create a temporary credentials file – all fine and well but getting that to fly without access to the file system is proving elusive and I can’t find any examples on how to go about it.
I’m currently just using Auth0 as a gateway to allow users to provide creds/access to my app for their account which works dandy, the proper scope items are requested (I’m just using read only file access for testing) – I get an bearer token and refresh token from them – however when trying to actually use that data and just do a simple file listing, I get a 400 bad request error.
I’m sure this must be possible but I can’t find any examples anywhere that deviate from the slightest of using the JSON file downloaded from Google and creating a credentials file – surely you can create an instance of the DriveService object armed with only the bearer token...
Anyway – here’s a chunk of test code I’m trying to get the driveService object configured – if anyone has done this or has suggestions as to what to try here I’d very much appreciate your thoughts.
public bool AuthenticationTest(string pBearerToken)
{
try
{
var oInit = new BaseClientService.Initializer
{
ApplicationName = "MyApp",
ApiKey = pBearerToken,
};
_googleDrive = new DriveService(oInit);
FilesResource.ListRequest listRequest = _googleDrive.Files.List();
listRequest.PageSize = 10;
listRequest.Fields = "nextPageToken, files(id, name)";
//All is well till this call to list the files…
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute().Files;
foreach (var file in files)
{
Debug. WriteLine(file.Name);
}
}
catch (Exception ex)
{
RaiseError(ex);
}
}
Yesterday afternoon I started having a problem where my google drive app could no longer update google documents. I can still update other file types like docx or rtf. This also happened to a coworker here but two different users are still able to use the google drive app and update google documents without issue, and we're all using the same build.
I logged into one of the working google accounts instead of my own and was not able to update that same google document that a coworker was able to. However the coworker that was having the same problem as me logged into a different google account and he was able to update google documents with the same build as before.
What the hell has happened here all of a sudden? This was working for us all two days ago.
This is where I request permissions:
GoogleWebAuthorizationBroker.Folder = "Tasks.Auth.Store";
StoredCredential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { DriveService.Scope.Drive,
DriveService.Scope.DriveFile },
"user",
CancellationToken.None,
new SavedDataStore()).Result;
I know the fileID going into it so:
request = service.Files.Get(fileID);
myFile = request.Execute();
While working with google documents I download it as a docx file and so:
if (myFile.MimeType == "application/vnd.google-apps.document")
myFile.MimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
And this is where the update happens:
try
{
//fileLoc contains the updated contents
byte[] byteArray = System.IO.File.ReadAllBytes(fileLoc);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
FilesResource.UpdateMediaUpload updateRequest = service.Files.Update(myFile, fileID, stream, myFile.MimeType);
//fileID is used to get myFile in the first place; myFile is = to myFile.Id
updateRequest.Upload();
}
catch (Exception e)
{
MessageBox.Show("An error occurred: " + e.Message);
}
This request happens without throwing any error and even updates the timestamp on these files but the content does not update. I am losing my mind trying to figure this out, I don't know what has gone wrong and I have no idea where to start looking.
There was a temporary glitch, this should be working again now.
I was trying to get the version of my extension at run-time using chrome.app.getDetails().version and noticed that chrome.app.getDetails() returns null. Surprisingly, there is no talk about this in the online community and the function isn't even documented by the Google folks. Is there a permission I am missing? I do have tabs enabled.
Very old... I know
But in case if someone is looking for this, you can have your extension version reading the manifest file with chrome.runtime API and the getManifest Method.
Ex. in your background script:
var manifest = chrome.runtime.getManifest();
var current_version = manifest.version;
console.info('Current Version: ', current_version);
The object returned is a serialization of the full manifest file, so you can get all the info in the manifest file
So.. if you want for example all and only the matches of your content_scripts... for say something...
for(var i in manifest.content_scripts) {
console.log(manifest.content_scripts[i]['matches']));
}
Note: Stable since Chrome 22
It's undocumented because they might be moving getDetails to a different part of the API -- see this bug. It's currently working on my copy of Chrome (beta channel), but I wouldn't be surprised if they've disabled it in a newer release. In the meantime you can just do an AJAX query to get the manifest.json of your extension -- you can get its URI using chrome.extension.getURL("manifest.json").
Here is what I'm using to pull the current version.
var manifest = new XMLHttpRequest();
manifest.open("get", "/manifest.json", true);
manifest.onreadystatechange = function (e) { if (manifest.readyState == 4) {console.log(JSON.parse(manifest.responseText).version)} };
manifest.send({});
Question I think is self explanatory, but if you need more, here it is:
Chrome Extension A saves an email address in localstorage.
Chrome Extension B wants to see that email address.
Is this permitted? (This might be more of an HTML5 thing than a Chrome-specific thing, but my knowledge is limited so I'll frame it within the context of my desire to know the answer).
If you own the two extensions, for instance, your the one maintaining both extensions. You can definitely use cross extension message communication to pass that email or even localStorage to the other extension.
For example, take a look at my extension here:
https://github.com/mohamedmansour/reload-all-tabs-extension/tree/v2
One extension is the core, and the other one is just the browser action (right now they are merged as of v3) but v2 lets them both communicate to each other. The browser action sends a "ping" event, and the core extension listens on such event and returns a "pong". The browser action extension is an "Add-On" to the core extension. When you open up "Options", it uses the options from the core one.
Back to your questions ... To access localStorage cross extensions, you can do something like this:
main core extension:
localStorage['foo'] = 'bar';
var secondary_extension_id = 'pecaecnbopekjflcoeeiogjaogdjdpoe';
chrome.extension.onRequestExternal.addListener(
function(request, sender, response) {
// Verify the request is coming from the Add-On.
if (sender.id != secondary_extension_id)
return;
// Handle the request.
if (request.getLocalStorage) {
response({result: localStorage});
} else {
response({}); // Snub them.
}
}
);
secondary extension:
var main_extension_id = 'gighmmpiobklfepjocnamgkkbiglidom'
chrome.extension.sendRequest(main_extension_id, {getLocalStorage: 1},
function (response) {
var storage = response.result;
alert(storage['foo']); // This should print out 'bar'.
}
);
BTW, I really didn't test this extension. I just copied and pasted from the reload all tabs extension that did something similar.
Not directly, but you can send messages between extensions. So if an extension that stores emails is expecting a request from some external extension, it could read the required data and send it back. More about it here.