Skip to content

Commit

Permalink
Only register the service worker when downloading a file
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Edwards committed Jul 6, 2024
1 parent eb3e1e4 commit 7b0cee4
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 12 deletions.
10 changes: 9 additions & 1 deletion Crypter.API/Controllers/FileTransferController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,15 @@ public FileTransferController(ISender sender)
{
_sender = sender;
}


/// <summary>
/// The ideal way to upload a file of any size.
/// However, the endpoints to receive chunked files is preferred while this Chromium issue remains unaddressed:
/// https://issues.chromium.org/issues/339788214
/// </summary>
/// <param name="username"></param>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
[MaybeAuthorize]
[RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue)]
Expand Down
22 changes: 20 additions & 2 deletions Crypter.Web/Npm/src/fileSaver/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,37 @@ function createDownloadIframe(src: string) {
return iframe;
}

export async function registerServiceWorker() :Promise<void> {
export async function registerServiceWorkerInternal() :Promise<void> {
if (serviceWorkerNotSupported()) {
throw new Error('Saving file via stream is not supported by this browser');
}

await navigator.serviceWorker.register('/serviceWorker',{
scope: '/'
}).then((x) => {
console.log("Service worker registered");
console.log("Registered service worker");
});

serviceWorkerKeepAlive();
}

export async function unregisterServiceWorkerInternal() : Promise<void> {
if (serviceWorkerNotSupported()) {
return;
}

const serviceWorkerRegistrations = await navigator.serviceWorker.getRegistrations();
for (const registration of serviceWorkerRegistrations) {
await registration.unregister().then(x => {
if (x) {
console.log("Unregistered service worker");
} else {
console.error("Failed to unregister service worker.")
}
});
}
}

export async function openDownloadStream(metaData: FileMetaData) {
const channel = new MessageChannel();
const stream = new WritableStream({
Expand Down
17 changes: 13 additions & 4 deletions Crypter.Web/Npm/src/fileSaver/fileSaver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* Modified date: April 2024
*/

import { registerServiceWorker, openDownloadStream } from "./download";
import {registerServiceWorkerInternal, openDownloadStream, unregisterServiceWorkerInternal} from "./download";
import { saveAs } from "file-saver";
import FileMetaData from "./interfaces/fileMetaData";
import DotNetStream from "./interfaces/dotNetStream";
Expand All @@ -17,15 +17,19 @@ class FileSaver {
private static _instance: FileSaver;
public IsServiceWorkerAvailable: boolean = false;

public async initializeAsync() {
await registerServiceWorker()
public async initialize() {
await registerServiceWorkerInternal()
.then(() => this.IsServiceWorkerAvailable = true)
.catch((error) : void => {
this.IsServiceWorkerAvailable = false;
console.warn('Saving file will fallback to buffered downloads:', error.message);
});
}

public async unregisterServiceWorker() {
await unregisterServiceWorkerInternal();
}

public static getInstance(): FileSaver
{
return this._instance || (this._instance = new this());
Expand Down Expand Up @@ -77,7 +81,12 @@ class FileSaver {

export async function initializeAsync() : Promise<void> {
let thisInstance: FileSaver = FileSaver.getInstance();
await thisInstance.initializeAsync();
await thisInstance.initialize();
}

export async function unregisterServiceWorkerAsync() : Promise<void> {
let thisInstance: FileSaver = FileSaver.getInstance();
await thisInstance.unregisterServiceWorker();
}

export function browserSupportsStreamingDownloads(): boolean {
Expand Down
12 changes: 11 additions & 1 deletion Crypter.Web/Services/FileSaverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public interface IFileSaverService
bool SupportsStreamingDownloads { get; }

Task InitializeAsync();
Task UnregisterServiceWorkerAsync();
Task SaveFileAsync(Stream stream, string fileName, string mimeType, long? size);
}

Expand All @@ -51,10 +52,19 @@ public async Task InitializeAsync()
if (OperatingSystem.IsBrowser())
{
_moduleReference = await jsRuntime.InvokeAsync<IJSInProcessObjectReference>("import", "../js/dist/fileSaver/fileSaver.bundle.js");
await _moduleReference.InvokeVoidAsync("initializeAsync");
await _moduleReference.InvokeVoidAsync("registerServiceWorker");
}
}

public async Task UnregisterServiceWorkerAsync()
{
if (OperatingSystem.IsBrowser())
{
_moduleReference = await jsRuntime.InvokeAsync<IJSInProcessObjectReference>("import", "../js/dist/fileSaver/fileSaver.bundle.js");
await _moduleReference.InvokeVoidAsync("unregisterServiceWorker");
}
}

public async Task SaveFileAsync(Stream stream, string fileName, string mimeType, long? size)
{
using DotNetStreamReference streamReference = new DotNetStreamReference(stream, leaveOpen: false);
Expand Down
1 change: 0 additions & 1 deletion Crypter.Web/Shared/MainLayout.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ protected override async Task OnInitializedAsync()
await Task.WhenAll(new Task[]
{
BlazorSodiumService.InitializeAsync(),
FileSaverService.InitializeAsync(),
BrowserFunctions.InitializeAsync()
});

Expand Down
6 changes: 3 additions & 3 deletions Crypter.Web/Shared/Transfer/DownloadFileTransfer.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ public partial class DownloadFileTransfer
[Inject]
private IJSRuntime JSRuntime { get; init; } = null!;

[Inject]
private IFileSaverService FileSaverService { get; init; } = null!;

protected bool FileCannotBeDownloadedOnThisBrowser { get; set; } = false;

private long _maxBufferSizeMB = 0;
Expand Down Expand Up @@ -97,6 +94,8 @@ private async Task OnDecryptClickedAsync(MouseEventArgs _)
ErrorMessage = "Download handler not assigned.";
return;
}

await FileSaverService.InitializeAsync();

DecryptionInProgress = true;

Expand All @@ -116,6 +115,7 @@ await decryptionResponse
.DoRightAsync(async decryptionStream =>
{
await FileSaverService.SaveFileAsync(decryptionStream, _fileName, _contentType, null);
await FileSaverService.UnregisterServiceWorkerAsync();
DecryptionComplete = true;
await decryptionStream.DisposeAsync();
})
Expand Down
2 changes: 2 additions & 0 deletions Crypter.Web/Shared/Transfer/DownloadMessageTransfer.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ private async Task OnDecryptClickedAsync(MouseEventArgs _)
ErrorMessage = "Download handler not assigned.";
return;
}

await FileSaverService.UnregisterServiceWorkerAsync();

DecryptionInProgress = true;

Expand Down
3 changes: 3 additions & 0 deletions Crypter.Web/Shared/Transfer/DownloadTransferBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
using Crypter.Common.Client.Transfer;
using Crypter.Common.Client.Transfer.Models;
using Crypter.Common.Enums;
using Crypter.Web.Services;
using EasyMonads;
using Microsoft.AspNetCore.Components;
using Microsoft.IdentityModel.Tokens;
Expand All @@ -49,6 +50,8 @@ public class DownloadTransferBase : ComponentBase

[Inject] protected ClientTransferSettings TransferSettings { get; init; } = null!;

[Inject] protected IFileSaverService FileSaverService { get; init; } = null!;

[Parameter] public required string TransferHashId { get; set; }

[Parameter] public TransferUserType UserType { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions Crypter.Web/Shared/Transfer/UploadFileTransfer.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ protected async Task OnEncryptClicked()
EncryptionInProgress = true;
ErrorMessage = string.Empty;

await FileSaverService.UnregisterServiceWorkerAsync();

await SetProgressMessageAsync("Encrypting file");

UploadFileHandler fileUploader = TransferHandlerFactory.CreateUploadFileHandler(FileStreamOpener,
Expand Down
2 changes: 2 additions & 0 deletions Crypter.Web/Shared/Transfer/UploadMessageTransfer.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public partial class UploadMessageTransfer : IDisposable

protected async Task OnEncryptClicked()
{
await FileSaverService.UnregisterServiceWorkerAsync();

EncryptionInProgress = true;
ErrorMessage = string.Empty;

Expand Down
3 changes: 3 additions & 0 deletions Crypter.Web/Shared/Transfer/UploadTransferBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
using Crypter.Common.Client.Transfer.Models;
using Crypter.Common.Contracts.Features.Transfer;
using Crypter.Common.Enums;
using Crypter.Web.Services;
using Crypter.Web.Shared.Modal;
using EasyMonads;
using Microsoft.AspNetCore.Components;
Expand All @@ -52,6 +53,8 @@ public class UploadTransferBase : ComponentBase

[Inject] protected TransferHandlerFactory TransferHandlerFactory { get; init; } = null!;

[Inject] protected IFileSaverService FileSaverService { get; init; } = null!;

[Parameter] public Maybe<string> RecipientUsername { get; set; }

[Parameter] public Maybe<byte[]> RecipientPublicKey { get; set; }
Expand Down

0 comments on commit 7b0cee4

Please sign in to comment.