From a7dbab71cfd74df131c1c2158b71c53c4bee6dfc Mon Sep 17 00:00:00 2001 From: Fergal Moran Date: Sat, 12 May 2018 05:47:43 +0100 Subject: [PATCH] Fix SignalR client in web to use connection pooling --- client/src/app/app.component.ts | 2 +- .../entry-list-item.component.ts | 4 +- client/src/app/services/chat.service.ts | 2 +- client/src/app/services/signalr.service.ts | 54 ++++++++++++++----- .../Repositories/PodcastRepository.cs | 9 +++- 5 files changed, 52 insertions(+), 19 deletions(-) diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 5f75394..b81ead3 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -59,7 +59,7 @@ export class AppComponent implements OnInit { this._signalrService .init('userupdates') .then((listener) => { - listener.on(chatterChannel) + listener.on('userupdates', chatterChannel) .subscribe(result => { this._toastyService.info(result); }); diff --git a/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts b/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts index a057f36..7447f46 100644 --- a/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts +++ b/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts @@ -48,13 +48,13 @@ export class EntryListItemComponent implements OnInit { this.entry.uid }__info_processed`; listener - .on(updateChannel) + .on('audioprocessing', updateChannel) .subscribe((result) => { this.percentageProcessed = result.percentage; this.currentSpeed = result.currentSpeed; }); listener - .on(processedChannel) + .on('audioprocessing', processedChannel) .subscribe((result) => { this.entry = result; if (this.entry.processingStatus === 'Processed') { diff --git a/client/src/app/services/chat.service.ts b/client/src/app/services/chat.service.ts index 41c1c78..80f6e89 100644 --- a/client/src/app/services/chat.service.ts +++ b/client/src/app/services/chat.service.ts @@ -26,7 +26,7 @@ export class ChatService extends BaseService { if (r) { this._signalRService.init('chat').then((listener) => { listener - .on('SendMessage') + .on('chat', 'SendMessage') .subscribe((message: ChatModel) => { console.log( 'chat-widget.component', diff --git a/client/src/app/services/signalr.service.ts b/client/src/app/services/signalr.service.ts index a9452f3..35fd5ef 100644 --- a/client/src/app/services/signalr.service.ts +++ b/client/src/app/services/signalr.service.ts @@ -4,34 +4,62 @@ import { HubConnection, HubConnectionBuilder, LogLevel } from '@aspnet/signalr'; import { environment } from 'environments/environment'; import { Observable, Subscriber } from 'rxjs'; +class HubListener { + constructor(connection: HubConnection) { + this.connection = connection; + this.isConnecting = false; + this.isConnected = false; + } + connection: HubConnection; + isConnected: boolean; + isConnecting: boolean; +} +interface HubCollection { + [hubName: string]: HubListener; +} + @Injectable() export class SignalRService { - private _connected: boolean = false; - private _connection: HubConnection; + private connectionPool: HubCollection = {}; constructor(private _auth: PodnomsAuthService) {} - public init(hub: string): Promise { + public init(hubName: string): Promise { return new Promise((resolve) => { - const url = `${environment.SIGNALR_HOST}/hubs/${hub}`; + const url = `${environment.SIGNALR_HOST}/hubs/${hubName}`; const token = this._auth.getToken(); - this._connection = new HubConnectionBuilder() - .configureLogging(LogLevel.Debug) - .withUrl(url + '?token=' + token) - .build(); + let hub = this.connectionPool[hubName]; + if (!hub) { + const connection = new HubConnectionBuilder() + .configureLogging(LogLevel.Debug) + .withUrl(url + '?token=' + token) + .build(); + this.connectionPool[hubName] = new HubListener(connection); + } resolve(this); }); } - public on(channel: string): Observable { + public on(hub: string, channel: string): Observable { const listener = new Observable((subscriber: Subscriber) => { - this._connection.on(channel, (message) => { + const h = this.connectionPool[hub]; + h.connection.on(channel, (message) => { const result: T = message as T; subscriber.next(result); }); + h.connection.onclose(() => { + h.isConnected = false; + }); + if (!h.isConnected && !h.isConnecting) { + h.isConnecting = true; + h.connection.start().then(() => { + h.isConnected = true; + h.isConnecting = false; + this.connectionPool[hub] = h; + }); + } + this.connectionPool[hub] = h; }); - if (!this._connected) { - this._connection.start().then(() => (this._connected = true)); - } + return listener; } } diff --git a/server/Persistence/Repositories/PodcastRepository.cs b/server/Persistence/Repositories/PodcastRepository.cs index ba1c072..bcbcd3e 100644 --- a/server/Persistence/Repositories/PodcastRepository.cs +++ b/server/Persistence/Repositories/PodcastRepository.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using PodNoms.Api.Models; +using PodNoms.Api.Utils; namespace PodNoms.Api.Persistence { public interface IPodcastRepository : IRepository { @@ -21,7 +22,6 @@ namespace PodNoms.Api.Persistence { .FirstOrDefaultAsync(); return ret; } - public async Task> GetAllForUserAsync(string userId) { var ret = GetAll() .Where(u => u.AppUser.Id == userId) @@ -29,6 +29,11 @@ namespace PodNoms.Api.Persistence { .OrderByDescending(p => p.Id); return await ret.ToListAsync(); } - + public new Podcast AddOrUpdate(Podcast podcast) { + if (string.IsNullOrEmpty(podcast.TemporaryImageUrl)) { + podcast.TemporaryImageUrl = $"standard/podcast-image-{Randomisers.RandomInteger(1, 16)}.png"; + } + return base.AddOrUpdate(podcast); + } } } \ No newline at end of file