Skip to content

Commit

Permalink
feat: GH Pages initial displayable wasm webapp
Browse files Browse the repository at this point in the history
  • Loading branch information
amis92 committed Apr 22, 2020
1 parent 1d64c56 commit c666862
Show file tree
Hide file tree
Showing 19 changed files with 571 additions and 8 deletions.
15 changes: 15 additions & 0 deletions GodMode.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WarHub.GodMode.Components",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WarHub.GodMode.SourceAnalysis", "src\WarHub.GodMode.SourceAnalysis\WarHub.GodMode.SourceAnalysis.csproj", "{4AB89A61-2CBB-4B01-B956-CAF45D3A5A4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WarHub.GodMode.GithubPages", "src\WarHub.GodMode.GithubPages\WarHub.GodMode.GithubPages.csproj", "{D122F971-3169-44F7-B560-317A9B034370}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -57,6 +59,18 @@ Global
{4AB89A61-2CBB-4B01-B956-CAF45D3A5A4B}.Release|x64.Build.0 = Release|Any CPU
{4AB89A61-2CBB-4B01-B956-CAF45D3A5A4B}.Release|x86.ActiveCfg = Release|Any CPU
{4AB89A61-2CBB-4B01-B956-CAF45D3A5A4B}.Release|x86.Build.0 = Release|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Debug|x64.ActiveCfg = Debug|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Debug|x64.Build.0 = Debug|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Debug|x86.ActiveCfg = Debug|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Debug|x86.Build.0 = Debug|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Release|Any CPU.Build.0 = Release|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Release|x64.ActiveCfg = Release|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Release|x64.Build.0 = Release|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Release|x86.ActiveCfg = Release|Any CPU
{D122F971-3169-44F7-B560-317A9B034370}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -65,6 +79,7 @@ Global
{D828D047-2598-4F18-B86C-AC3382BB0506} = {F2C4E8DB-68F0-4ED3-AAAD-009183BB5ADD}
{2E086252-718E-490E-B886-F3A2B570E9FB} = {F2C4E8DB-68F0-4ED3-AAAD-009183BB5ADD}
{4AB89A61-2CBB-4B01-B956-CAF45D3A5A4B} = {F2C4E8DB-68F0-4ED3-AAAD-009183BB5ADD}
{D122F971-3169-44F7-B560-317A9B034370} = {F2C4E8DB-68F0-4ED3-AAAD-009183BB5ADD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {838E0D3E-F95E-483C-BEBE-DCE7BC1A93FB}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ public sealed partial class WorkspaceInfo

public string AppRoute => appRoute ??= Type switch
{
WorkspaceType.GitHub => $"/gh/{GitHubRepository}",
WorkspaceType.LocalFilesystem => "/",
_ => throw new InvalidOperationException()
WorkspaceType.GitHub => $"gh/{GitHubRepository}",
WorkspaceType.LocalFilesystem => "",
_ => ""
};

public static WorkspaceInfo Invalid { get; } = new WorkspaceInfo(WorkspaceType.Invalid, null, null);

public static WorkspaceInfo CreateLocalFs(string path)
=> new WorkspaceInfo(WorkspaceType.LocalFilesystem, path, null);

Expand Down
10 changes: 10 additions & 0 deletions src/WarHub.GodMode.GithubPages/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
118 changes: 118 additions & 0 deletions src/WarHub.GodMode.GithubPages/Pages/Index.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
@page "/"
@page "/gh/{GitHubOwner}/{GitHubRepository}"

@using WarHub.ArmouryModel.ProjectModel
@using WarHub.GodMode.Components.Areas.Workspace

@inject NavigationManager Navman
@inject IWorkspaceProviderAggregate ProviderAggregate

<Title>@TitleText</Title>

<RepositorySourceSelect WorkspaceInfo="WorkspaceInfo" WorkspaceInfoChanged="UpdateWorkspace" />

@if (ErrorMessage is null)
{
if (Workspace is { })
{
<WorkspaceView Workspace="Workspace" />
}
else if (WorkspaceInfo.Type == WorkspaceType.Invalid)
{
<em>No workspace loaded.</em>
}
else
{
<em>Loading source...</em>
}
}
else
{
<h4>@ErrorMessage</h4>
}

@code {
[Parameter]
public string GitHubOwner { get; set; }

[Parameter]
public string GitHubRepository { get; set; }

string TitleText => WorkspaceInfo?.Type switch
{
WorkspaceType.GitHub => WorkspaceInfo.GitHubRepository,
_ => "GodMode"
};

WorkspaceInfo FallbackWorkspaceInfo => WorkspaceInfo.Invalid;

IWorkspace Workspace { get; set; }

WorkspaceInfo WorkspaceInfo { get; set; } = WorkspaceInfo.Invalid;

string ErrorMessage { get; set; }

(WorkspaceInfo info, string error) ParseLocation()
{
if (string.IsNullOrEmpty(GitHubOwner) || string.IsNullOrEmpty(GitHubRepository))
{
return (null, null);
}
var urlString = $"https://github.com/{GitHubOwner}/{GitHubRepository}";
try
{
var url = new Uri(urlString);
var info = WorkspaceInfo.CreateGitHub(url);
return (info, null);
}
catch (Exception e)
{
var msg = $"Failed to parse GitHub address '{urlString}': " + e.Message;
return (null, msg);
}
}

protected override async Task OnParametersSetAsync()
{
await Update();
}

protected override async Task OnInitializedAsync()
{
await Update();
}

async Task Update()
{
var (info, message) = ParseLocation();
ErrorMessage = message;
await UpdateWorkspace(info ?? FallbackWorkspaceInfo);
}

async Task UpdateWorkspace(WorkspaceInfo info)
{
if (WorkspaceInfo != info || Workspace == null)
{
WorkspaceInfo = info;
Workspace = null;
ErrorMessage = null;
try
{
if (info.Type != WorkspaceType.Invalid)
{
Workspace = await ProviderAggregate.GetWorkspace(info);
}
}
catch (Exception e)
{
ErrorMessage = $"Failed to load repository source: {e.Message}";
}
var targetUri = Navman.ToAbsoluteUri(Navman.BaseUri + info.AppRoute).ToString();
if (targetUri != Navman.Uri)
{
Navman.NavigateTo(targetUri);
}
StateHasChanged();
}
}
}
32 changes: 32 additions & 0 deletions src/WarHub.GodMode.GithubPages/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Toolbelt.Blazor.Extensions.DependencyInjection;
using WarHub.GodMode.Components.Areas.Workspace;
using WarHub.GodMode.GithubPages.Services;

namespace WarHub.GodMode.GithubPages
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");

builder.Services.AddSingleton(new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
ConfigureServices(builder.Services);

await builder.Build().RunAsync();
}
static void ConfigureServices(IServiceCollection services)
{
services.AddHeadElementHelper();
services.AddSingleton<GitHubWorkspaceProvider>();
services.AddScoped<IWorkspaceProviderAggregate, WorkspaceProviderAggregate>();
services.AddScoped<IWorkspaceContextResolver, WorkspaceContextResolver>();
}
}
}
31 changes: 31 additions & 0 deletions src/WarHub.GodMode.GithubPages/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:19082",
"sslPort": 44340
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"commandLineArgs": "--pathbase=/GodMode",
"launchBrowser": true,
"launchUrl": "GodMode",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
},
"WarHub.GodMode.GithubPages": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
}
}
}
116 changes: 116 additions & 0 deletions src/WarHub.GodMode.GithubPages/Services/GitHubWorkspaceProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Threading.Tasks;
using WarHub.ArmouryModel.ProjectModel;
using WarHub.ArmouryModel.Source;
using WarHub.ArmouryModel.Workspaces.BattleScribe;
using WarHub.GodMode.Components.Areas.Workspace;

namespace WarHub.GodMode.GithubPages.Services
{
public class GitHubWorkspaceProvider : IWorkspaceProvider
{
public GitHubWorkspaceProvider(HttpClient httpClient)
{
HttpClient = httpClient;
}

private HttpClient HttpClient { get; }

// TODO cache -> IndexedDB
private Dictionary<Uri, IWorkspace> Cache { get; }
= new Dictionary<Uri, IWorkspace>();

public async Task<IWorkspace> GetWorkspace(WorkspaceInfo info)
{
if (info is { Type: WorkspaceType.GitHub, GitHubUrl: { } })
{
return await GetWorkspaceCore(info);
}
return null;
}

public async Task<IWorkspace> GetWorkspaceCore(WorkspaceInfo info)
{
if (Cache.TryGetValue(info.GitHubUrl, out var cached))
{
return cached;
}
return await Task.Run(async () =>
{
var repoPath = string.Concat(info.GitHubUrl.Segments[^2..]);
var repoUri = info.GitHubUrl + "/archive/master.zip";
var response = await HttpClient.GetAsync(repoUri);
response.EnsureSuccessStatusCode();
using var zipStream = await response.Content.ReadAsStreamAsync();
using var zip = new ZipArchive(zipStream);
var datafiles = GetDatafiles(zip).ToImmutableArray();
var workspace = new InMemoryWorkspace(info.GitHubUrl.ToString(), datafiles);
return Cache[info.GitHubUrl] = workspace;
});

IEnumerable<IDatafileInfo> GetDatafiles(ZipArchive zip)
{
foreach (var entry in zip.Entries)
{
using var entryStream = entry.Open();
var file = entry.Name.GetXmlDocumentKind() switch
{
XmlDocumentKind.Gamesystem => entryStream.LoadSourceAuto(entry.Name),
XmlDocumentKind.Catalogue => entryStream.LoadSourceAuto(entry.Name),
_ => (IDatafileInfo)new UnknownTypeDatafileInfo(entry.Name)
};
if (file is { })
{
yield return file;
}
}
}
}

private class InMemoryWorkspace : IWorkspace
{
public InMemoryWorkspace(string rootPath, ImmutableArray<IDatafileInfo> datafiles)
{
RootPath = rootPath;
Datafiles = datafiles;
}

public string RootPath { get; }

public ImmutableArray<IDatafileInfo> Datafiles { get; }

public ProjectConfigurationInfo Info { get; } = new ProjectConfigurationInfo.Builder
{
Filepath = ProjectConfiguration.FileExtension,
Configuration = new ProjectConfiguration.Builder
{
FormatProvider = ProjectFormatProviderType.BattleScribeXml,
OutputPath = ".",
SourceDirectories = ImmutableArray<SourceFolder>.Empty,
ToolsetVersion = ProjectToolset.Version
}.ToImmutable()
}.ToImmutable();
}

private class UnknownTypeDatafileInfo : IDatafileInfo
{
public UnknownTypeDatafileInfo(string filepath)
{
Filepath = filepath;
}

public string Filepath { get; }

public SourceKind DataKind => SourceKind.Unknown;

public SourceNode GetData() => null;

public string GetStorageName() => Path.GetFileNameWithoutExtension(Filepath);
}
}
}
Loading

0 comments on commit c666862

Please sign in to comment.