Skip to content

Commit

Permalink
Merge pull request #201 from sebagomez/fix/slashed-files
Browse files Browse the repository at this point in the history
Fixes issue with non-prod like Azurite urls
  • Loading branch information
sebagomez authored Dec 9, 2024
2 parents 71776bf + 7bb87b6 commit b26e2a0
Show file tree
Hide file tree
Showing 24 changed files with 178 additions and 55 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
bin/
obj/
.vs/

.DS_Store
**/wwwroot/dist/
!**/**/wwwroot/dist/azurewebexplorer.css
**/Properties/launchSettings.json
Expand All @@ -12,5 +12,4 @@ obj/
__azurite*.json
private*.data

.DS_Store
azurestorageexplorer.sln
23 changes: 22 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,28 @@
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
//"AZURE_STORAGE_CONNECTIONSTRING": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;QueueEndpoint=http://localhost:10001/devstoreaccount1;TableEndpoint=http://localhost:10002/devstoreaccount1;"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": "Blazor WEB (Azurite)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-and-azurite",
"program": "${workspaceFolder}/src/web/bin/Debug/net8.0/web.dll",
"args": [],
"cwd": "${workspaceFolder}/src/web",
"stopAtEntry": false,
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"AZURE_STORAGE_CONNECTIONSTRING": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;QueueEndpoint=http://localhost:10001/devstoreaccount1;TableEndpoint=http://localhost:10002/devstoreaccount1;",
"AZURITE": "true"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
Expand Down
9 changes: 9 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
],
"problemMatcher": "$msCompile"
},
{
"label": "azurite",
"command": "./azurite.sh"
},
{
"label": "build-and-azurite",
"dependsOrder": "sequence",
"dependsOn": ["build", "azurite"]
},
{
"label": "publish",
"command": "dotnet",
Expand Down
18 changes: 18 additions & 0 deletions azurite.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

CONTAINER_NAME="azurite"
IMAGE_NAME="mcr.microsoft.com/azure-storage/azurite"

Check if the container is already running
if [ "$(docker ps -q -f name=${CONTAINER_NAME})" ]; then
echo "Container ${CONTAINER_NAME} is already running."
else
# Check if the container exists but is stopped
if [ "$(docker ps -aq -f status=exited -f name=${CONTAINER_NAME})" ]; then
echo "Starting existing container ${CONTAINER_NAME}."
docker start ${CONTAINER_NAME}
else
echo "Running a new container named ${CONTAINER_NAME}."
docker run -d -p 10000:10000 -p 10001:10001 -p 10002:10002 --name ${CONTAINER_NAME} ${IMAGE_NAME}
fi
fi
3 changes: 2 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
cd "${0%/*}" || exit 1
#!/bin/bash

dotnet build ./src/web/web.csproj
3 changes: 2 additions & 1 deletion docker-build.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
cd "${0%/*}" || exit 1
#!/bin/bash

docker build --tag azurestorageexplorer:local ./src
3 changes: 1 addition & 2 deletions docker-compose/azurestorageexplorer.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.8'

services:
azurite:
image: mcr.microsoft.com/azure-storage/azurite
Expand All @@ -14,5 +12,6 @@ services:
- "8080:8080"
environment:
- AZURE_STORAGE_CONNECTIONSTRING=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;TableEndpoint=http://azurite:10002/devstoreaccount1;
- AZURITE=true
depends_on:
- azurite
2 changes: 1 addition & 1 deletion docker-run.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cd "${0%/*}" || exit 1
#!/bin/bash

echo App will run on http://localhost:8080

Expand Down
40 changes: 40 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
default:
@just --list

# Build the solution
build:
dotnet build ./src/web/web.csproj

# Publish and launches in localhost:5000
publish:
#!/bin/bash
dotnet publish --configuration Release -o ./bin ./src/web/web.csproj

OK=$?
if [ $OK -eq 0 ]; then
echo Azure Storage Explorer will be running in http://localhost:5000/
cd bin
dotnet web.dll
cd ..
fi

# Run unit tests
test:
dotnet test ./tests/StorageLibTests/StorageLibTests.csproj

# Build Docker image as azurestorageexplorer:local
db:
docker build --tag azurestorageexplorer:local ./src

# Launches the local docker image at http://localhost:8080
dr:
echo App will run on http://localhost:8080
docker run --rm -p 8080:8080 --name azurestorageexplorer azurestorageexplorer:local

compose:
docker-compose -f ./docker-compose/azurestorageexplorer.yaml up

uncompose:
docker-compose -f ./docker-compose/azurestorageexplorer.yaml down


2 changes: 1 addition & 1 deletion publish.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cd "${0%/*}" || exit 1
#!/bin/bash

dotnet publish --configuration Release -o ./bin ./src/web/web.csproj

Expand Down
2 changes: 1 addition & 1 deletion src/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0 as builder
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS builder

WORKDIR /src
COPY ./ /src
Expand Down
8 changes: 4 additions & 4 deletions src/StorageLibrary/AzureContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ namespace StorageLibrary
{
internal class AzureContainer : StorageObject, IContainer
{
public AzureContainer(string account, string key, string endpoint, string connectionString)
: base(account, key, endpoint, connectionString) { }
public AzureContainer(StorageFactoryConfig config)
: base(config) { }

public async Task<List<CloudBlobContainerWrapper>> ListContainersAsync()
{
Expand Down Expand Up @@ -45,11 +45,11 @@ public async Task<List<BlobItemWrapper>> ListBlobsAsync(string containerName, st
{
BlobClient blobClient = container.GetBlobClient(blobItem.Blob.Name);

wrapper = new BlobItemWrapper(blobClient.Uri.AbsoluteUri, blobItem.Blob.Properties.ContentLength);
wrapper = new BlobItemWrapper(blobClient.Uri.AbsoluteUri, blobItem.Blob.Properties.ContentLength.HasValue ? blobItem.Blob.Properties.ContentLength.Value : 0, IsAzurite);
}
else if (blobItem.IsPrefix)
{
wrapper = new BlobItemWrapper($"{container.Uri}/{blobItem.Prefix}", 0);
wrapper = new BlobItemWrapper($"{container.Uri}/{blobItem.Prefix}", 0, IsAzurite);
}

if (wrapper != null && !results.Contains(wrapper))
Expand Down
4 changes: 2 additions & 2 deletions src/StorageLibrary/AzureFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace StorageLibrary
{
internal class AzureFile : StorageObject, IFile
{
public AzureFile(string account, string key, string endpoint, string connectionString)
: base(account, key, endpoint, connectionString) { }
public AzureFile(StorageFactoryConfig config)
: base(config) { }

public async Task<List<FileShareWrapper>> ListFileSharesAsync()
{
Expand Down
5 changes: 3 additions & 2 deletions src/StorageLibrary/AzureQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ namespace StorageLibrary
{
internal class AzureQueue : StorageObject, IQueue
{
public AzureQueue(string account, string key, string endpoint, string connectionString)
: base(account, key, endpoint, connectionString) { }
public AzureQueue(StorageFactoryConfig config)
: base(config) { }

public async Task<List<QueueWrapper>> ListQueuesAsync()
{
QueueServiceClient client = new QueueServiceClient(ConnectionString);
Expand Down
4 changes: 2 additions & 2 deletions src/StorageLibrary/AzureTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ namespace StorageLibrary
{
internal class AzureTable : StorageObject, ITable
{
public AzureTable(string account, string key, string endpoint, string connectionString)
: base(account, key, endpoint, connectionString) { }
public AzureTable(StorageFactoryConfig config)
: base(config) { }

public async Task<List<TableWrapper>> ListTablesAsync()
{
Expand Down
30 changes: 13 additions & 17 deletions src/StorageLibrary/Common/BlobItemWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,18 @@ namespace StorageLibrary.Common
public class BlobItemWrapper : IEquatable<BlobItemWrapper>, IComparable<BlobItemWrapper>
{
Uri m_internalUri;
public string Name { get => HttpUtility.UrlDecode(m_internalUri.Segments[m_internalUri.Segments.Length - 1]); }
public string Path
{
get
{
int containerPos = m_internalUri.LocalPath.IndexOf(Container) + Container.Length;

return m_internalUri.LocalPath.Substring(containerPos, (m_internalUri.LocalPath.Length) - (containerPos) - Name.Length);
}
}

public string Container { get => IsAzurite ? m_internalUri.Segments[2] : m_internalUri.Segments[1]; }
bool m_isAzurite = false;
public string Name { get; private set; }
public string Path { get; private set; }
public string Container { get; private set; }
public string FullName { get => $"{Path}{Name}"; }
public bool IsFile { get => !m_internalUri.Segments[m_internalUri.Segments.Length - 1].EndsWith("/"); }
public bool IsFile { get; private set; }
public string Url
{
get { return m_internalUri.OriginalString; }
private set { m_internalUri = new Uri(value); }
}

public bool IsAzurite { get => m_internalUri.IsLoopback; }

public long Size { get; private set; }

public decimal SizeInKBs { get => (decimal)Size / 1024; }
Expand All @@ -36,10 +26,16 @@ public string Url

public BlobItemWrapper(string url) : this(url, 0) { }

public BlobItemWrapper(string url, long? size)
public BlobItemWrapper(string url, long size, bool fromAzurite = false)
{
Url = url;
Size = size.HasValue ? size.Value : 0;
Size = size;
m_isAzurite = fromAzurite;
IsFile = !m_internalUri.Segments[m_internalUri.Segments.Length - 1].EndsWith(System.IO.Path.AltDirectorySeparatorChar);
Container = m_isAzurite ? m_internalUri.Segments[2] : m_internalUri.Segments[1];
Name = HttpUtility.UrlDecode(m_internalUri.Segments[m_internalUri.Segments.Length - 1]);
int containerPos = m_internalUri.LocalPath.IndexOf(Container) + Container.Length;
Path = m_internalUri.LocalPath.Substring(containerPos, (m_internalUri.LocalPath.Length) - (containerPos) - Name.Length);
}

public int CompareTo(BlobItemWrapper other)
Expand Down
2 changes: 1 addition & 1 deletion src/StorageLibrary/Mocks/MockContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ await Task.Run(() =>
if (MockUtils.FolderStructure[containerName].Contains(blobName))
throw new InvalidOperationException($"Blob '{blobName}' already exists in Container '{containerName}'");

BlobItemWrapper blob = new BlobItemWrapper($"{MockUtils.FAKE_URL}/{containerName}/{blobName}");
BlobItemWrapper blob = StorageFactory.GetBlobItemWrapper($"{MockUtils.FAKE_URL}/{containerName}/{blobName}");
if (!MockUtils.FolderStructure[containerName].Contains(blob.Path))
MockUtils.FolderStructure[containerName].Add(blob.Path);

Expand Down
35 changes: 29 additions & 6 deletions src/StorageLibrary/StorageFactory.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@

using StorageLibrary.Common;
using StorageLibrary.Interfaces;
using StorageLibrary.Mocks;

namespace StorageLibrary
{
public class StorageFactory
{
static StorageFactory Instance;

public IQueue Queues { get; private set; }
public IContainer Containers { get; set; }
public ITable Tables { get; set; }
public IFile Files { get; set; }

StorageFactoryConfig m_currentConfig;

public StorageFactory()
: this(string.Empty, string.Empty, string.Empty, string.Empty, true)
: this(new StorageFactoryConfig { Mock = true })
{ }

public StorageFactory(string account, string key, string endpoint, string connectionString, bool mock = false)
public StorageFactory(StorageFactoryConfig config)
{
Queues = mock ? new MockQueue() : new AzureQueue(account, key, endpoint, connectionString);
Containers = mock ? new MockContainer() : new AzureContainer(account, key, endpoint, connectionString);
Tables = mock ? new MockTable() : new AzureTable(account, key, endpoint, connectionString);
Files = mock ? new MockFile() : new AzureFile(account, key, endpoint, connectionString);
m_currentConfig = config;
Queues = config.Mock ? new MockQueue() : new AzureQueue(config);
Containers = config.Mock ? new MockContainer() : new AzureContainer(config);
Tables = config.Mock ? new MockTable() : new AzureTable(config);
Files = config.Mock ? new MockFile() : new AzureFile(config);

Instance = this;
}

public static BlobItemWrapper GetBlobItemWrapper(string url, long size = 0)
{
return new BlobItemWrapper(url, size, Instance.m_currentConfig.IsAzurite);
}
}

public class StorageFactoryConfig
{
public string Account { get; set; }
public string Key { get; set; }
public string Endpoint { get; set; } = "core.windows.net";
public string ConnectionString { get; set; }
public bool IsAzurite { get; set; }
public bool Mock { get; set; }
}
}
9 changes: 8 additions & 1 deletion src/StorageLibrary/StorageObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@ internal class StorageObject
public string Endpoint { get; private set; } = "core.windows.net";
public string ConnectionString { get; private set; }

public bool IsAzurite { get; private set; }

const string CONNSTRING_TEMPLATE = "DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}";
public StorageObject(string account, string key, string endpoint, string connectionString)

public StorageObject(StorageFactoryConfig config)
: this(config.Account, config.Key, config.Endpoint, config.ConnectionString, config.IsAzurite){ }

public StorageObject(string account, string key, string endpoint, string connectionString, bool azurite)
{
IsAzurite = azurite;
if (!string.IsNullOrEmpty(connectionString))
{
ConnectionString = connectionString;
Expand Down
2 changes: 1 addition & 1 deletion src/web/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<AzureStorageWebExplorerVersion>2.17.0</AzureStorageWebExplorerVersion>
<AzureStorageWebExplorerVersion>2.17.1</AzureStorageWebExplorerVersion>
</PropertyGroup>
</Project>
Loading

0 comments on commit b26e2a0

Please sign in to comment.