@@ -24,11 +24,12 @@ ILogger<ProjectServicesProvider> logger
2424 private IProjectProvider ? FwDataProjectProvider =>
2525 projectProviders . FirstOrDefault ( p => p . DataFormat == ProjectDataFormat . FwData ) ;
2626 internal readonly ConcurrentDictionary < ProjectScope , ProjectScope > _projectScopes = new ( ) ;
27+
2728 public async ValueTask DisposeAsync ( )
2829 {
2930 foreach ( var projectScope in _projectScopes . Values )
3031 {
31- await ( projectScope . Cleanup ? . Value . DisposeAsync ( ) ?? ValueTask . CompletedTask ) ;
32+ await projectScope . CleanupAsync ( ) ;
3233 }
3334 }
3435
@@ -46,73 +47,112 @@ public async Task DisposeService(DotNetObjectReference<IAsyncDisposable> service
4647 }
4748
4849 [ JSInvokable ]
49- public async Task < ProjectScope > OpenCrdtProject ( string code )
50+ public Task < ProjectScope > OpenCrdtProject ( string code )
5051 {
51- var serviceScope = serviceProvider . CreateAsyncScope ( ) ;
52- var scopedServices = serviceScope . ServiceProvider ;
53- var project = crdtProjectsService . GetProject ( code )
54- ?? throw new InvalidOperationException ( $ "Crdt Project { code } not found") ;
55- var server = lexboxProjectService . GetServer ( project . Data ) ;
56- var currentProjectService = scopedServices . GetRequiredService < CurrentProjectService > ( ) ;
57- var projectData = await currentProjectService . SetupProjectContext ( project ) ;
58- await scopedServices . GetRequiredService < SyncService > ( ) . SafeExecuteSync ( true ) ;
59- await lexboxProjectService . ListenForProjectChanges ( projectData , CancellationToken . None ) ;
60- var miniLcm = ActivatorUtilities . CreateInstance < MiniLcmJsInvokable > ( scopedServices , project ) ;
61- var scope = new ProjectScope ( Defer . Async ( ( ) =>
62- {
63- logger . LogInformation ( "Disposing project scope {ProjectName}" , projectData . Name ) ;
64- return Task . CompletedTask ;
65- } ) , serviceScope , this , projectData . Name , miniLcm ,
66- ActivatorUtilities . CreateInstance < HistoryServiceJsInvokable > ( scopedServices ) ,
67- ActivatorUtilities . CreateInstance < SyncServiceJsInvokable > ( scopedServices ) )
52+ return Task . Run ( async ( ) =>
6853 {
69- ProjectData = projectData ,
70- Server = server
71- } ;
72- _projectScopes . TryAdd ( scope , scope ) ;
73- return scope ;
54+ var serviceScope = serviceProvider . CreateAsyncScope ( ) ;
55+ ProjectScope ? scope = null ;
56+ try
57+ {
58+ var scopedServices = serviceScope . ServiceProvider ;
59+ var project = crdtProjectsService . GetProject ( code )
60+ ?? throw new InvalidOperationException ( $ "Crdt Project { code } not found") ;
61+ var server = lexboxProjectService . GetServer ( project . Data ) ;
62+ var currentProjectService = scopedServices . GetRequiredService < CurrentProjectService > ( ) ;
63+ var projectData = await currentProjectService . SetupProjectContext ( project ) ;
64+ await scopedServices . GetRequiredService < SyncService > ( ) . SafeExecuteSync ( true ) ;
65+ await lexboxProjectService . ListenForProjectChanges ( projectData , CancellationToken . None ) ;
66+ var miniLcm = ActivatorUtilities . CreateInstance < MiniLcmJsInvokable > ( scopedServices , project ) ;
67+ scope = ProjectScope . Create ( serviceScope , this , projectData . Name , miniLcm ) ;
68+ scope . ProjectData = projectData ;
69+ scope . Server = server ;
70+ scope . SetCrdtServices (
71+ ActivatorUtilities . CreateInstance < HistoryServiceJsInvokable > ( scopedServices ) ,
72+ ActivatorUtilities . CreateInstance < SyncServiceJsInvokable > ( scopedServices )
73+ ) ;
74+ _projectScopes . TryAdd ( scope , scope ) ;
75+ return scope ;
76+ }
77+ catch
78+ {
79+ if ( scope is not null ) await scope . CleanupAsync ( ) ;
80+ else await serviceScope . DisposeAsync ( ) ;
81+ throw ;
82+ }
83+ } ) ;
7484 }
7585
7686 [ JSInvokable ]
77- public async Task < ProjectScope > OpenFwDataProject ( string projectName )
87+ public Task < ProjectScope > OpenFwDataProject ( string projectName )
7888 {
79- var serviceScope = serviceProvider . CreateAsyncScope ( ) ;
80- var scopedServices = serviceScope . ServiceProvider ;
81- if ( FwDataProjectProvider is null )
82- throw new InvalidOperationException ( "FwData Project provider is not available" ) ;
83- var project = FwDataProjectProvider . GetProject ( projectName ) ??
84- throw new InvalidOperationException ( $ "FwData Project { projectName } not found") ;
85- var miniLcm = ActivatorUtilities . CreateInstance < MiniLcmJsInvokable > ( scopedServices ,
86- await FwDataProjectProvider . OpenProject ( project , scopedServices ) ,
87- project ) ;
88- var scope = new ProjectScope ( Defer . Async ( ( ) =>
89+ return Task . Run ( async ( ) =>
8990 {
90- logger . LogInformation ( "Disposing fwdata project scope {ProjectName}" , projectName ) ;
91- return Task . CompletedTask ;
92- } ) , serviceScope , this , projectName , miniLcm , null , null ) ;
93- _projectScopes . TryAdd ( scope , scope ) ;
94- return scope ;
91+ var serviceScope = serviceProvider . CreateAsyncScope ( ) ;
92+ ProjectScope ? scope = null ;
93+ try
94+ {
95+ var scopedServices = serviceScope . ServiceProvider ;
96+ if ( FwDataProjectProvider is null )
97+ throw new InvalidOperationException ( "FwData Project provider is not available" ) ;
98+ var project = FwDataProjectProvider . GetProject ( projectName ) ??
99+ throw new InvalidOperationException ( $ "FwData Project { projectName } not found") ;
100+ var miniLcm = ActivatorUtilities . CreateInstance < MiniLcmJsInvokable > (
101+ scopedServices ,
102+ await FwDataProjectProvider . OpenProject ( project , scopedServices ) ,
103+ project
104+ ) ;
105+ scope = ProjectScope . Create ( serviceScope , this , projectName , miniLcm ) ;
106+ _projectScopes . TryAdd ( scope , scope ) ;
107+ return scope ;
108+ }
109+ catch
110+ {
111+ if ( scope is not null ) await scope . CleanupAsync ( ) ;
112+ else await serviceScope . DisposeAsync ( ) ;
113+ throw ;
114+ }
115+ } ) ;
95116 }
96117}
97118
98119public class ProjectScope
99120{
100- public ProjectScope ( IAsyncDisposable cleanup ,
121+ private static readonly ObjectFactory < ProjectScope > ProjectScopeFactory =
122+ ActivatorUtilities . CreateFactory < ProjectScope > (
123+ [
124+ typeof ( AsyncServiceScope ) ,
125+ typeof ( ProjectServicesProvider ) ,
126+ typeof ( string ) ,
127+ typeof ( MiniLcmJsInvokable )
128+ ] ) ;
129+ public static ProjectScope Create (
101130 AsyncServiceScope serviceScope ,
131+ ProjectServicesProvider projectServicesProvider ,
132+ string projectName ,
133+ MiniLcmJsInvokable miniLcm )
134+ {
135+ return ProjectScopeFactory . Invoke ( serviceScope . ServiceProvider ,
136+ [
137+ serviceScope ,
138+ projectServicesProvider ,
139+ projectName ,
140+ miniLcm
141+ ] ) ;
142+ }
143+
144+ public ProjectScope ( AsyncServiceScope serviceScope ,
102145 ProjectServicesProvider projectServicesProvider ,
103146 string projectName ,
104147 MiniLcmJsInvokable miniLcm ,
105- HistoryServiceJsInvokable ? historyService ,
106- SyncServiceJsInvokable ? syncService )
148+ ILogger < ProjectScope > logger )
107149 {
108150 ProjectName = projectName ;
109151 MiniLcm = DotNetObjectReference . Create ( miniLcm ) ;
110- HistoryService = historyService is null ? null : DotNetObjectReference . Create ( historyService ) ;
111- SyncService = syncService is null ? null : DotNetObjectReference . Create ( syncService ) ;
112152 Cleanup = DotNetObjectReference . Create ( Defer . Async ( async ( ) =>
113153 {
154+ logger . LogInformation ( "Disposing project scope {ProjectName}" , projectName ) ;
114155 projectServicesProvider . _projectScopes . TryRemove ( this , out _ ) ;
115- await cleanup . DisposeAsync ( ) ;
116156 if ( HistoryService is not null )
117157 {
118158 HistoryService . Dispose ( ) ;
@@ -131,10 +171,23 @@ public ProjectScope(IAsyncDisposable cleanup,
131171 } ) ) ;
132172 }
133173
174+ public void SetCrdtServices (
175+ HistoryServiceJsInvokable historyService ,
176+ SyncServiceJsInvokable syncService )
177+ {
178+ HistoryService = DotNetObjectReference . Create ( historyService ) ;
179+ SyncService = DotNetObjectReference . Create ( syncService ) ;
180+ }
181+
182+ public ValueTask CleanupAsync ( )
183+ {
184+ return Cleanup ? . Value . DisposeAsync ( ) ?? ValueTask . CompletedTask ;
185+ }
186+
134187 public DotNetObjectReference < IAsyncDisposable > ? Cleanup { get ; set ; }
135188 public string ProjectName { get ; set ; }
136189 public LexboxServer ? Server { get ; set ; }
137- public ProjectData ? ProjectData { get ; init ; }
190+ public ProjectData ? ProjectData { get ; set ; }
138191 public DotNetObjectReference < MiniLcmJsInvokable > MiniLcm { get ; set ; }
139192 public DotNetObjectReference < HistoryServiceJsInvokable > ? HistoryService { get ; set ; }
140193 public DotNetObjectReference < SyncServiceJsInvokable > ? SyncService { get ; set ; }
0 commit comments