/// <inheritdoc /> public async Task <BatchTransfer> RequestBatchAsync(GitHost host, string repositoryName, BatchRequest request) { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.git-lfs+json")); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", host.Token); using (var content = new StringContent( this.requestSerialiser.ToString(request), null, "application/vnd.git-lfs+json")) { HttpResponseMessage result = await client.PostAsync(GetLfsBatchUrl(host, repositoryName), content).ConfigureAwait(false); if (!result.IsSuccessStatusCode) { await this.HandleErrorAsync(result).ConfigureAwait(false); } string returnContents = await result.Content.ReadAsStringAsync().ConfigureAwait(false); return(this.transferSerialiser.TransferFromString(returnContents)); } } }
public async Task <IActionResult> Edit(int id, [Bind("Id,Href,Name,UserName,Token")] GitHost gitHost) { if (id != gitHost.Id) { return(this.NotFound()); } if (this.ModelState.IsValid) { try { this.context.Update(gitHost); await this.context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!this.GitHostExists(gitHost.Id)) { return(this.NotFound()); } throw; } return(this.RedirectToAction("Index")); } return(this.View(gitHost)); }
/// <inheritdoc /> public async Task <Stream> DownloadFileAsync( GitHost host, string repositoryName, ObjectId objectId, BatchObjectAction action) { using (var httpClient = new HttpClient()) { SetClientHeaders(action, httpClient); this.logger.LogInformation( $"Download from {action.HRef} with repository name {repositoryName}, request:{objectId.Hash.Substring(0, 10)}/{objectId.Size}"); HttpResponseMessage result = await httpClient.GetAsync(action.HRef, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); if (!result.IsSuccessStatusCode) { await this.HandleErrorAsync(result).ConfigureAwait(false); } this.logger.LogInformation( $"Now saving to a file {repositoryName}, request:{objectId.Hash.Substring(0, 10)}/{objectId.Size}\""); return(this.fileManager.SaveFile( out string fileName, repositoryName, objectId, FileLocation.Permanent, await result.Content.ReadAsStreamAsync().ConfigureAwait(false))); } }
public async Task <IActionResult> DeleteConfirmed(int id) { GitHost gitHost = await this.context.GitHost.SingleOrDefaultAsync(m => m.Id == id); this.context.GitHost.Remove(gitHost); await this.context.SaveChangesAsync(); return(this.RedirectToAction("Index")); }
public async Task <IActionResult> UploadFile(int hostId, string repositoryName, string objectId, long size) { var fileObjectId = new ObjectId(objectId, size); try { GitHost host = await this.context.GitHost.FindAsync(hostId); if (host == null) { this.logger.LogWarning("Not a valid host id"); return(this.NotFound(new ErrorResponse { Message = "Not a valid host id" })); } this.logger.LogInformation($"Saving the file to disk for {fileObjectId}"); this.Response.Headers.Remove("transfer-encoding"); if (!this.fileManager.IsFileStored( repositoryName, fileObjectId, FileLocation.Metadata, false, "upload")) { this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "upload"); return(this.Ok()); } BatchObjectAction action = this.transferSerialiser.ObjectActionFromString(await this.fileManager.GetFileContentsAsync(repositoryName, fileObjectId, FileLocation.Metadata, "upload")); this.logger.LogInformation($"Starting file upload for {fileObjectId}"); await this.lfsClient.UploadFile(action, this.Request.Body); this.logger.LogInformation($"Finished file upload for {fileObjectId}"); this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "upload"); return(this.Ok()); } catch (ErrorResponseException ex) { this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message} for {fileObjectId}"); this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Temporary); return(this.StatusCode(ex.StatusCode.Value, ex.ErrorResponse)); } catch (StatusCodeException ex) { this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message} for {fileObjectId}"); this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Temporary); return(this.StatusCode(ex.StatusCode.Value, new ErrorResponse { Message = ex.Message })); } }
public async Task <IActionResult> Create([Bind("Id,Href,Name,UserName,Token")] GitHost gitHost) { if (this.ModelState.IsValid) { this.context.Add(gitHost); await this.context.SaveChangesAsync(); return(this.RedirectToAction("Index")); } return(this.View(gitHost)); }
public async Task <IActionResult> Create([Bind("Href,Id,Name,Token,UserName")] GitHost gitHost) { if (this.ModelState.IsValid) { this.context.Add(gitHost); await this.context.SaveChangesAsync().ConfigureAwait(false); return(this.RedirectToAction(nameof(this.Index))); } return(this.View(gitHost)); }
/// <summary> /// Deltes a GitHost object from the database with the specified ID. /// </summary> /// <param name="id">The ID to delete.</param> /// <returns>A action result to monitor the progress.</returns> public async Task <IActionResult> Delete(int?id) { if (id == null) { return(this.NotFound()); } GitHost gitHost = await this.context.GitHost.SingleOrDefaultAsync(m => m.Id == id); if (gitHost == null) { return(this.NotFound()); } return(this.View(gitHost)); }
public async Task <IActionResult> Verify(int hostId, string repositoryName, string objectId, long size) { var fileObjectId = new ObjectId(objectId, size); try { GitHost host = await this.context.GitHost.FindAsync(hostId); if (host == null) { return(this.NotFound(new ErrorResponse { Message = "Not a valid host id." })); } this.fileManager.MoveFile(repositoryName, fileObjectId, FileLocation.Temporary, FileLocation.Permenant); if (this.fileManager.IsFileStored(repositoryName, fileObjectId, FileLocation.Metadata, false, "verify")) { this.logger.LogInformation($"Starting verify for {fileObjectId}"); BatchObjectAction action = this.transferSerialiser.ObjectActionFromString(await this.fileManager.GetFileContentsAsync(repositoryName, fileObjectId, FileLocation.Metadata, "verify")); await this.lfsClient.Verify(host, repositoryName, fileObjectId, action); this.logger.LogInformation($"Ending verify for {fileObjectId}"); } this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "verify"); return(this.Ok()); } catch (ErrorResponseException ex) { this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message} for {fileObjectId}"); return(this.StatusCode(ex.StatusCode.Value, ex.ErrorResponse)); } catch (StatusCodeException ex) { this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message} for {fileObjectId}"); return(this.StatusCode(ex.StatusCode.Value, new ErrorResponse { Message = ex.Message })); } }
private void UserControl_Loaded(object sender, RoutedEventArgs e) { if (DesignerProperties.GetIsInDesignMode(this)) { return; } if (!GitLocator.IsGitInstalled) { MessageBox.Show($"Git is not installed or not found at the default install path.\nSearch Path was: {GitLocator.GitPath}", "Git not found", MessageBoxButton.OK, MessageBoxImage.Error); } if (_gitHost == null) { _gitHost = new GitHost(GitLocator.GitPath); RootGrid.Children.Clear(); RootGrid.Children.Add(_gitHost); } }
/// <inheritdoc /> public async Task VerifyAsync(GitHost host, string repositoryName, ObjectId objectId, BatchObjectAction action) { using (var httpClient = new HttpClient()) { SetClientHeaders(action, httpClient); using (var content = new StringContent( this.verifySerialiser.ToString(objectId), null, "application/vnd.git-lfs+json")) { this.logger.LogInformation( $"Verify from {action.HRef} with repository name {repositoryName}, request:{objectId.Hash.Substring(0, 10)}/{objectId.Size}"); HttpResponseMessage result = await httpClient.PostAsync(action.HRef, content).ConfigureAwait(false); if (!result.IsSuccessStatusCode) { await this.HandleErrorAsync(result).ConfigureAwait(false); } } } }
private async Task HandleHttpRequest(HttpContext context) { PathString path = context.Request.Path; if (path.ToString().Contains("lfs")) { await this.next(context); return; } var matchCriteria = new Regex("/api/([0-9]+)/([a-zA-Z0-9-\\.]*/?.*)"); Match match = matchCriteria.Match(context.Request.Path.ToString()); if (match.Success == false) { await this.next(context); return; } var dbContext = context.RequestServices.GetService <ApplicationDbContext>(); if (int.TryParse(match.Groups[1].Value, out int hostIndex) == false) { await this.next(context); return; } GitHost gitHost = await dbContext.GitHost.SingleOrDefaultAsync(x => x.Id == hostIndex); if (gitHost == null) { await this.next(context); return; } var requestMessage = new HttpRequestMessage(); string requestMethod = context.Request.Method; if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod)) { var streamContent = new StreamContent(context.Request.Body); requestMessage.Content = streamContent; } // Copy the request headers foreach (KeyValuePair <string, StringValues> header in context.Request.Headers) { if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null) { requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); } } string newPath = match.Groups[2].Value; var uri = new Uri($"{gitHost.Href}/{context.Request.PathBase}{newPath}{context.Request.QueryString}"); requestMessage.Headers.Host = uri.Host; requestMessage.RequestUri = uri; requestMessage.Method = new HttpMethod(context.Request.Method); using (HttpResponseMessage responseMessage = await this.httpClient.SendAsync( requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted)) { context.Response.StatusCode = (int)responseMessage.StatusCode; foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Headers) { context.Response.Headers[header.Key] = header.Value.ToArray(); } foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Content.Headers) { context.Response.Headers[header.Key] = header.Value.ToArray(); } // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response. context.Response.Headers.Remove("transfer-encoding"); await responseMessage.Content.CopyToAsync(context.Response.Body); } }
private static Uri GetLfsBatchUrl(GitHost host, string repositoryName) { return(new Uri($"{host.Href}/{repositoryName}/info/lfs/objects/batch")); }
public async Task <IActionResult> DownloadFile(int hostId, string repositoryName, string objectId, long size) { var fileObjectId = new ObjectId(objectId, size); try { GitHost host = await this.context.GitHost.FindAsync(hostId).ConfigureAwait(false); if (host == null) { return(this.NotFound(new ErrorResponse { Message = "Not a valid host id." })); } Stream stream = this.fileManager.GetFileStream(repositoryName, fileObjectId, FileLocation.Permanent); if (stream != null) { this.logger.LogInformation($"Found local cache file: {fileObjectId}"); return(this.File(stream, "application/octet-stream")); } var actionStream = await this.fileManager.GetFileContentsAsync(repositoryName, fileObjectId, FileLocation.Metadata, "download").ConfigureAwait(false); if (actionStream == null) { this.logger.LogWarning($"No valid batch request for {fileObjectId}"); return(this.NotFound(new ErrorResponse { Message = $"No valid batch request for {fileObjectId}" })); } BatchObjectAction action = this.transferSerialiser.ObjectActionFromString(actionStream); if (action == null) { this.logger.LogWarning($"Unable to find file {objectId}"); return(this.NotFound(new ErrorResponse { Message = $"Unable to find file {objectId}" })); } if (action.Mode != BatchActionMode.Download) { this.logger.LogWarning($"No download action associated with request: {objectId}"); return(this.StatusCode( 422, new ErrorResponse { Message = $"No download action associated with request: {objectId}" })); } this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "download"); return(this.File( await this.lfsClient.DownloadFileAsync( host, repositoryName, fileObjectId, action).ConfigureAwait(false), "application/octet-stream")); } catch (ErrorResponseException ex) { this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message} for {fileObjectId}"); return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, ex.ErrorResponse)); } catch (StatusCodeException ex) { this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message}"); return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, new ErrorResponse { Message = ex.Message })); } }
public async Task <IActionResult> HandleBatchRequest( int hostId, string repositoryName, [FromBody] BatchRequest request) { GitHost host = await this.context.GitHost.FindAsync(hostId).ConfigureAwait(false); if (host == null) { return(this.NotFound(new ErrorResponse { Message = "Not a valid host id." })); } var serverBatchRequest = new BatchRequest { Objects = new List <ObjectId>(), Operation = request.Operation, Transfers = request.Transfers }; foreach (ObjectId objectId in request.Objects) { if (request.Operation == BatchRequestMode.Download && this.fileManager.IsFileStored(repositoryName, objectId, FileLocation.Permanent)) { continue; } serverBatchRequest.Objects.Add(objectId); } try { IDictionary <ObjectId, IBatchObject> batchObjects = new Dictionary <ObjectId, IBatchObject>(); if (serverBatchRequest.Objects.Count > 0) { BatchTransfer serverResults = await this.lfsClient.RequestBatchAsync(host, repositoryName, serverBatchRequest).ConfigureAwait(false); foreach (IBatchObject serverResult in serverResults.Objects) { batchObjects.Add(serverResult.Id, serverResult); if (serverResult is BatchObject batchObject) { foreach (BatchObjectAction action in batchObject.Actions) { await this.fileManager.SaveFileAsync( repositoryName, serverResult.Id, FileLocation.Metadata, this.transferSerialiser.ToString(action), action.Mode.ToString().ToLowerInvariant()).ConfigureAwait(false); } } } } var returnResult = new BatchTransfer(); returnResult.Mode = TransferMode.Basic; returnResult.Objects = new List <IBatchObject>(); foreach (ObjectId pendingObjectId in request.Objects) { batchObjects.TryGetValue(pendingObjectId, out IBatchObject batchObjectBase); var batchObject = batchObjectBase as BatchObject; if (batchObjectBase is BatchObjectError errorResult) { returnResult.Objects.Add(errorResult); } else { switch (request.Operation) { case BatchRequestMode.Upload: returnResult.Objects.Add(batchObject); break; case BatchRequestMode.Download: { var returnBatchObject = new BatchObject { Id = pendingObjectId, Actions = new List <BatchObjectAction>() }; var action = new BatchObjectAction { Mode = BatchActionMode.Download, HRef = $"{this.Request.Scheme}://{this.Request.Host}/api/{hostId}/{repositoryName}/info/lfs/{pendingObjectId.Hash}/{pendingObjectId.Size}" }; returnBatchObject.Actions.Add(action); returnResult.Objects.Add(returnBatchObject); break; } } } } return(this.Ok(returnResult)); } catch (ErrorResponseException ex) { this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message}"); return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, ex.ErrorResponse)); } catch (StatusCodeException ex) { this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message}"); return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, new ErrorResponse { Message = ex.Message })); } }