This commit is contained in:
danielgrabowski 2019-11-07 11:52:27 +01:00
parent 527be316ff
commit 7ee7ebc4b3
31 changed files with 127 additions and 388 deletions

View File

@ -17,7 +17,6 @@ namespace Squirrowse.Client
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
services.AddSingleton<IConnectionManager>(x =>
new ConnectionManager("http://localhost", 5000)); //keep as transient for now

View File

@ -10,12 +10,13 @@ namespace Squirrowse.Client.Service
{
public class ActionDispatcher : IActionDispatcher
{
private readonly ICameraService camera;
private readonly IConnectionManager connectionManager;
private readonly ILogger<ActionDispatcher> logger;
private readonly HubConnection session;
private readonly ICameraService camera;
public ActionDispatcher(ILogger<ActionDispatcher> logger, IConnectionManager connectionManager,ICameraService camera)
public ActionDispatcher(ILogger<ActionDispatcher> logger, IConnectionManager connectionManager,
ICameraService camera)
{
this.connectionManager = connectionManager;
this.logger = logger;

View File

@ -21,4 +21,4 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
</Project>

View File

@ -23,12 +23,7 @@ namespace Squirrowse.Client
public async Task StartAsync(CancellationToken cancellationToken)
{
for (int i = 0; i < 100; i++)
{
await _connectionManager.InitConnection(ConnectionType.Client);
}
for (var i = 0; i < 100; i++) await _connectionManager.InitConnection(ConnectionType.Client);
}
public async Task StopAsync(CancellationToken cancellationToken)

View File

@ -9,7 +9,7 @@ namespace Squirrowse.Core
public static IServiceCollection AddCoreModule(this IServiceCollection services)
{
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddSingleton<IConnectionManager>(x =>
services.AddSingleton<IConnectionManager, ConnectionManager>(x =>
new ConnectionManager("http://localhost", 5000));
return services;
}

View File

@ -2,7 +2,7 @@
{
public enum ConnectionType
{
Unknown=-1,
Unknown = -1,
Client,
Server,
Root

View File

@ -6,7 +6,7 @@
{
ConnectionId = connectionId;
AgentName = agentName;
this.UserType = userType;
UserType = userType;
}
public string ConnectionId { get; set; }

View File

@ -31,8 +31,7 @@ namespace Squirrowse.Core.Services
{
if (_connection.State == HubConnectionState.Connected) return;
await _connection.StartAsync();
// await RegisterOnHub(type);
await SpamHub(type);
await RegisterOnHub(type);
Connected = true;
}
@ -46,17 +45,7 @@ namespace Squirrowse.Core.Services
private async Task RegisterOnHub(ConnectionType type)
{
await _connection.SendAsync("AddUser", Environment.UserName,type);
}
#warning debug
private async Task SpamHub(ConnectionType type)
{
for (int i = 0; i < 100; i++)
{
await _connection.SendAsync("AddUser", Environment.UserName + $"{DateTime.Now}", type);
}
await _connection.SendAsync("AddUser", Environment.UserName, type);
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squirrowse.Core.Models;
@ -7,7 +6,7 @@ namespace Squirrowse.Service.Hubs
{
public interface IStreamHub
{
Task AddUser(string username,ConnectionType type);
Task AddUser(string username, ConnectionType type);
Task UploadByteStream(IAsyncEnumerable<byte[]> stream);
Task Startstream(string userId);
Task StopStream(string userId);

View File

@ -6,10 +6,10 @@ namespace Squirrowse.Service.Hubs
{
public interface IStreamManager
{
Task AddUser(string connectionId, string agentName,ConnectionType type);
Task AddUser(string connectionId, string agentName, ConnectionType type);
Task RemoveUserbyConnectionId(string connectionId);
Task RemoveUserByUserName(string agentName);
IEnumerable<User> getServerSideUsers();
IEnumerable<User> getServerSideUsers();
bool CheckUser(string agentName);
IEnumerable<User> getClientSideUsers();
IEnumerable<User> getAllUsers();

View File

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
using Squirrowse.Core.Models;
using Squirrowse.Core.Services;
namespace Squirrowse.Service.Hubs
{
@ -23,9 +20,8 @@ namespace Squirrowse.Service.Hubs
public async Task AddUser(string UserName, ConnectionType type)
{
await manager.AddUser(Context.ConnectionId, UserName,type);
await manager.AddUser(Context.ConnectionId, UserName, type);
logger.LogInformation($"{nameof(AddUser)}: {UserName} of {type}");
}
@ -71,13 +67,11 @@ namespace Squirrowse.Service.Hubs
public async Task UploadByteStream(IAsyncEnumerable<byte[]> stream)
{
foreach (var user in manager.getServerSideUsers())
{
await Clients.Client(user.ConnectionId).SendAsync("RecData", stream);
}
await foreach (var frame in stream)
await foreach (var frame in stream)
{
logger.LogInformation($"Got frame size: {frame.Length} ");
await Task.Delay(100); //leave some delay for debug purpose
await Task.Delay(100); //leave some delay for debug purpose
}
}
@ -85,42 +79,18 @@ namespace Squirrowse.Service.Hubs
{
if (t == ConnectionType.Client) return manager.getClientSideUsers();
if (t == ConnectionType.Server) return manager.getServerSideUsers();
throw new Exception("not found") ;
}
#warning DEBUG
public async Task<string> GetListOfTypeUserString()
{
string t = "";
var tasdf=manager.getClientSideUsers();
foreach (var h in tasdf)
{
t +=h.AgentName;
}
return t;
}
#warning DEBUG
public async Task<User> Getasuser() => manager.getClientSideUsers().FirstOrDefault();
#warning Debug
public async Task<List<User>> GetListOfTypeUserE(ConnectionType t)
{
if (t == ConnectionType.Client) return manager.getClientSideUsers().ToList();
if (t == ConnectionType.Server) return manager.getServerSideUsers().ToList();
throw new Exception("not found");
}
#warning debug
public async IAsyncEnumerable<User> GetListOfTypeUserAsync(ConnectionType t)
{
var client = manager.getClientSideUsers();
foreach (var va in client)
{
await Task.Delay(500);
yield return va;
}
}
public async Task<IEnumerable<User>> GetAllUsers()
{
return manager.getAllUsers();
}
public async IAsyncEnumerable<User> GetListOfTypeUserAsync(ConnectionType t)
{
var client = await GetListOfTypeUser(t);
foreach (var va in client) yield return va;
}
}
}

View File

@ -7,11 +7,11 @@ namespace Squirrowse.Service.Hubs
{
public class StreamManager : IStreamManager
{
private List<User> _users = new List<User>(); //temporary
private readonly List<User> _users = new List<User>(); //temporary
public Task AddUser(string connectionId, string userName,ConnectionType type)
public Task AddUser(string connectionId, string userName, ConnectionType type)
{
_users.Add(new User(connectionId, userName,type));
_users.Add(new User(connectionId, userName, type));
return Task.CompletedTask;
}
@ -31,10 +31,12 @@ namespace Squirrowse.Service.Hubs
{
return _users.Where(user => user.UserType == ConnectionType.Server);
}
public IEnumerable<User> getClientSideUsers()
{
return _users.Where(user => user.UserType == ConnectionType.Client);
}
public bool CheckUser(string userName)
{
return _users.Any(user => user.AgentName == userName);

View File

@ -1,10 +1,10 @@
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</Router>

View File

@ -1,15 +0,0 @@
using System;
namespace Squirrowse.Web.Data
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
}

View File

@ -1,25 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Squirrowse.Web.Data
{
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
}
}

View File

@ -1,16 +0,0 @@
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
}

View File

@ -1,16 +0,0 @@
@page "/error"
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@ -1,46 +0,0 @@
@page "/fetchdata"
@using Squirrowse.Web.Data
@inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
}

View File

@ -32,27 +32,8 @@
</div>
</div>
}
}
@*<div class="card-body">
<div>
<h3 class="badge-primary">
@agents.AgentName -> @agents.UserType.ToString()
</h3>
<div style="padding-top:10px">
<button id="ViewCast" disabled="@(IsViewingCastOf(agents.AgentName))" class="btn btn-success btn-sm" @onclick="@(() => OnViewCastClicked(agents.ConnectionId))">
View cast
</button>
<button id="StopViewCast" disabled="@(!IsViewingCastOf(agents.AgentName))" class="btn btn-warning btn-sm" @onclick="@(() => OnStopViewCastClicked(agents.ConnectionId))">
Stop cast
</button>
</div>
</div>
</div>*@
else
}
else
{
<div class="card-body">
<h3 class="card-header badge-warning">No Cams</h3>
@ -73,48 +54,25 @@ else
protected override async Task OnInitializedAsync()
{
// agents=new List<User>();
await _connection.InitConnection(ConnectionType.Server);
connection = await _connection.GetConnection();
connection.On<IAsyncEnumerable<byte[]>>("RecData", OnStreamDataReceived);
//agents = await connection.InvokeAsync<string>("GetListOfTypeUserString");
//agents = await connection.InvokeAsync<User>("Getasuser");
//agents = await connection.InvokeAsync<IAsyncEnumerable<User>>("GetListOfTypeUserAsync",ConnectionType.Client);
await foreach (var dupa in connection.StreamAsync<User>("GetListOfTypeUserAsync", ConnectionType.Client).ConfigureAwait(false))
await foreach (var user in connection.StreamAsync<User>("GetListOfTypeUserAsync", ConnectionType.Client).ConfigureAwait(false))
{
agents.Add(dupa);
// await Task.Delay(300);
agents.Add(user);
this.StateHasChanged();
}
//connection.On<User>("NewUser", NewUser);
//connection.On<string>("RemoveScreenCastAgent", RemoveScreenCastAgent);
//connection.On<string>("OnStreamDataReceived", OnStreamDataReceived);
//await connection.StartAsync();
}
//cannot control enumerator
//protected override async Task OnAfterRenderAsync(bool firstRender=true)
//{
// await foreach (var dupa in connection.StreamAsync<User>("GetListOfTypeUserAsync", ConnectionType.Client))
// {
// agents.Add(dupa);
// await Task.Delay(300);
// this.StateHasChanged();
// }
//}
bool IsViewingCastOf(string agentName)
{
return agentName == CurrentViewCastAgent;
}
//void NewUser(User agentName)
//{
// agents.Add(agentName);
// StateHasChanged();
//}
async void OnStreamDataReceived(IAsyncEnumerable<byte[]> streamData)
{
await foreach (var t in streamData)

View File

@ -2,4 +2,4 @@
<h1>Hello, world!</h1>
Welcome to your new app.
Welcome to your new app.

View File

@ -5,18 +5,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Squirrowse.Web</title>
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<base href="~/"/>
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css"/>
<link href="css/site.css" rel="stylesheet"/>
</head>
<body>
<app>
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</app>
<app>
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</app>
<script src="_framework/blazor.server.js"></script>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
</html>

View File

@ -1,13 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Squirrowse.Web
{
@ -18,11 +10,10 @@ namespace Squirrowse.Web
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}
}
}
}

View File

@ -24,4 +24,4 @@
}
}
}
}
}

View File

@ -1,7 +1,7 @@
@inherits LayoutComponentBase
<div class="sidebar">
<NavMenu />
<NavMenu/>
</div>
<div class="main">
@ -12,4 +12,4 @@
<div class="content px-4">
@Body
</div>
</div>
</div>

View File

@ -1,42 +1,33 @@
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">Squirrowse.Web</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="Hub">
<span class="oi oi-list-rich" aria-hidden="true"></span> Stream
</NavLink>
</li>
</ul>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="Hub">
<span class="oi oi-list-rich" aria-hidden="true"></span> Stream
</NavLink>
</li>
</ul>
</div>
@code {
bool collapseNavMenu = true;
@code {
bool collapseNavMenu = true;
string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}

View File

@ -14,4 +14,8 @@
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Data\" />
</ItemGroup>
</Project>

View File

@ -1,16 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Squirrowse.Core;
using Squirrowse.Web.Data;
namespace Squirrowse.Web
{
@ -28,11 +21,10 @@ namespace Squirrowse.Web
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor().AddHubOptions(x=>x.MaximumReceiveMessageSize= 102400000);
services.AddServerSideBlazor().AddHubOptions(x => x.MaximumReceiveMessageSize = 102400000);
services.AddCoreModule();
services.AddSignalR().AddMessagePackProtocol();
services.AddSingleton<WeatherForecastService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -61,4 +53,4 @@ namespace Squirrowse.Web
});
}
}
}
}

View File

@ -6,4 +6,4 @@
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using Squirrowse.Web
@using Squirrowse.Web.Shared
@using Squirrowse.Web.Shared

View File

@ -6,4 +6,4 @@
"Microsoft": "Information"
}
}
}
}

View File

@ -7,4 +7,4 @@
}
},
"AllowedHosts": "*"
}
}

View File

@ -1,34 +1,28 @@
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; }
a, .btn-link {
color: #0366d6;
}
a, .btn-link { color: #0366d6; }
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
background-color: #1b6ec2;
border-color: #1861ac;
color: #fff;
}
app {
position: relative;
display: flex;
flex-direction: column;
position: relative;
}
.top-row {
height: 3.5rem;
display: flex;
align-items: center;
display: flex;
height: 3.5rem;
}
.main {
flex: 1;
}
.main { flex: 1; }
.main .top-row {
background-color: #f7f7f7;
@ -36,27 +30,19 @@ app {
justify-content: flex-end;
}
.main .top-row > a {
margin-left: 1.5rem;
}
.main .top-row > a { margin-left: 1.5rem; }
.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}
.sidebar { background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); }
.sidebar .top-row {
background-color: rgba(0,0,0,0.4);
}
.sidebar .top-row { background-color: rgba(0, 0, 0, 0.4); }
.sidebar .navbar-brand {
font-size: 1.1rem;
}
.sidebar .navbar-brand { font-size: 1.1rem; }
.sidebar .oi {
width: 2rem;
font-size: 1.1rem;
vertical-align: text-top;
top: -2px;
vertical-align: text-top;
width: 2rem;
}
.nav-item {
@ -64,69 +50,51 @@ app {
padding-bottom: 0.5rem;
}
.nav-item:first-of-type {
padding-top: 1rem;
}
.nav-item:first-of-type { padding-top: 1rem; }
.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item:last-of-type { padding-bottom: 1rem; }
.nav-item a {
color: #d7d7d7;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
border-radius: 4px;
color: #d7d7d7;
display: flex;
height: 3rem;
line-height: 3rem;
}
.nav-item a.active {
background-color: rgba(255,255,255,0.25);
background-color: rgba(255, 255, 255, 0.25);
color: white;
}
.nav-item a:hover {
background-color: rgba(255,255,255,0.1);
background-color: rgba(255, 255, 255, 0.1);
color: white;
}
.content {
padding-top: 1.1rem;
}
.content { padding-top: 1.1rem; }
.navbar-toggler {
background-color: rgba(255, 255, 255, 0.1);
}
.navbar-toggler { background-color: rgba(255, 255, 255, 0.1); }
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}
.valid.modified:not([type=checkbox]) { outline: 1px solid #26b050; }
.invalid {
outline: 1px solid red;
}
.invalid { outline: 1px solid red; }
.validation-message {
color: red;
}
.validation-message { color: red; }
@media (max-width: 767.98px) {
.main .top-row {
display: none;
}
.main .top-row { display: none; }
}
@media (min-width: 768px) {
app {
flex-direction: row;
}
app { flex-direction: row; }
.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
width: 250px;
}
.main .top-row {
@ -139,12 +107,10 @@ app {
padding-right: 1.5rem !important;
}
.navbar-toggler {
display: none;
}
.navbar-toggler { display: none; }
.sidebar .collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
}
}