11
11
12
12
namespace Coder . Desktop . App . Services ;
13
13
14
- public interface IUriHandler : IAsyncDisposable
14
+ public interface IUriHandler
15
15
{
16
16
public Task HandleUri ( Uri uri , CancellationToken ct = default ) ;
17
17
}
@@ -24,10 +24,16 @@ public class UriHandler(
24
24
{
25
25
private const string OpenWorkspacePrefix = "/v0/open/ws/" ;
26
26
27
- internal class UriException ( string title , string detail ) : Exception
27
+ internal class UriException : Exception
28
28
{
29
- internal readonly string Title = title ;
30
- internal readonly string Detail = detail ;
29
+ internal readonly string Title ;
30
+ internal readonly string Detail ;
31
+
32
+ internal UriException ( string title , string detail ) : base ( $ "{ title } : { detail } ")
33
+ {
34
+ Title = title ;
35
+ Detail = detail ;
36
+ }
31
37
}
32
38
33
39
public async Task HandleUri ( Uri uri , CancellationToken ct = default )
@@ -52,7 +58,7 @@ private async Task HandleUriThrowingErrors(Uri uri, CancellationToken ct = defau
52
58
53
59
logger . LogWarning ( "unhandled URI path {path}" , uri . AbsolutePath ) ;
54
60
throw new UriException ( "URI handling error" ,
55
- $ "URI with path { uri . AbsolutePath } is unsupported or malformed") ;
61
+ $ "URI with path ' { uri . AbsolutePath } ' is unsupported or malformed") ;
56
62
}
57
63
58
64
public async Task HandleOpenWorkspaceApp ( Uri uri , CancellationToken ct = default )
@@ -63,7 +69,7 @@ public async Task HandleOpenWorkspaceApp(Uri uri, CancellationToken ct = default
63
69
if ( components . Length != 4 || components [ 1 ] != "agent" )
64
70
{
65
71
logger . LogWarning ( "unsupported open workspace app format in URI {path}" , uri . AbsolutePath ) ;
66
- throw new UriException ( errTitle , $ "Failed to open { uri . AbsolutePath } because the format is unsupported.") ;
72
+ throw new UriException ( errTitle , $ "Failed to open ' { uri . AbsolutePath } ' because the format is unsupported.") ;
67
73
}
68
74
69
75
var workspaceName = components [ 0 ] ;
@@ -73,41 +79,38 @@ public async Task HandleOpenWorkspaceApp(Uri uri, CancellationToken ct = default
73
79
var state = rpcController . GetState ( ) ;
74
80
if ( state . VpnLifecycle != VpnLifecycle . Started )
75
81
{
76
- logger . LogDebug ( "got URI to open workspace {workspace}, but Coder Connect is not started" , workspaceName ) ;
82
+ logger . LogDebug ( "got URI to open workspace ' {workspace}' , but Coder Connect is not started" , workspaceName ) ;
77
83
throw new UriException ( errTitle ,
78
- $ "Failed to open application on { workspaceName } because Coder Connect is not started.") ;
84
+ $ "Failed to open application on ' { workspaceName } ' because Coder Connect is not started.") ;
79
85
}
80
86
81
- Workspace workspace ;
82
- try
83
- {
84
- workspace = state . Workspaces . Single ( w => w . Name == workspaceName ) ;
85
- }
86
- catch ( InvalidOperationException ) // Single() throws this when nothing matches.
87
- {
88
- logger . LogDebug ( "got URI to open workspace {workspace}, but the workspace doesn't exist" , workspaceName ) ;
87
+ var workspace = state . Workspaces . FirstOrDefault ( w => w . Name == workspaceName ) ;
88
+ if ( workspace == null ) {
89
+ logger . LogDebug ( "got URI to open workspace '{workspace}', but the workspace doesn't exist" , workspaceName ) ;
89
90
throw new UriException ( errTitle ,
90
- $ "Failed to open application on workspace { workspaceName } because it doesn't exist") ;
91
+ $ "Failed to open application on workspace ' { workspaceName } ' because it doesn't exist") ;
91
92
}
92
93
93
- Agent agent ;
94
- try
95
- {
96
- agent = state . Agents . Single ( a => a . WorkspaceId == workspace . Id && a . Name == agentName ) ;
97
- }
98
- catch ( InvalidOperationException ) // Single() throws this when nothing matches.
99
- {
100
- logger . LogDebug ( "got URI to open workspace/agent {workspaceName}/{agentName}, but the agent doesn't exist" ,
94
+ var agent = state . Agents . FirstOrDefault ( a => a . WorkspaceId == workspace . Id && a . Name == agentName ) ;
95
+ if ( agent == null ) {
96
+ logger . LogDebug ( "got URI to open workspace/agent '{workspaceName}/{agentName}', but the agent doesn't exist" ,
101
97
workspaceName , agentName ) ;
98
+ // If the workspace isn't running, that is almost certainly why we can't find the agent, so report that
99
+ // to the user.
100
+ if ( workspace . Status != Workspace . Types . Status . Running )
101
+ {
102
+ throw new UriException ( errTitle ,
103
+ $ "Failed to open application on workspace '{ workspaceName } ', because the workspace is not running.") ;
104
+ }
102
105
throw new UriException ( errTitle ,
103
- $ "Failed to open application on workspace { workspaceName } , agent { agentName } because it doesn't exist.") ;
106
+ $ "Failed to open application on workspace ' { workspaceName } ', because agent ' { agentName } ' doesn't exist.") ;
104
107
}
105
108
106
109
if ( appName != "rdp" )
107
110
{
108
111
logger . LogWarning ( "unsupported agent application type {app}" , appName ) ;
109
112
throw new UriException ( errTitle ,
110
- $ "Failed to open agent in URI { uri . AbsolutePath } because application { appName } is unsupported") ;
113
+ $ "Failed to open agent in URI ' { uri . AbsolutePath } ' because application ' { appName } ' is unsupported") ;
111
114
}
112
115
113
116
await OpenRDP ( agent . Fqdn . First ( ) , uri . Query , ct ) ;
@@ -137,14 +140,9 @@ public async Task OpenRDP(string domainName, string queryString, CancellationTok
137
140
if ( ! string . IsNullOrEmpty ( username ) )
138
141
{
139
142
password ??= string . Empty ;
140
- await rdpConnector . WriteCredentials ( domainName , new RdpCredentials ( username , password ) , ct ) ;
143
+ rdpConnector . WriteCredentials ( domainName , new RdpCredentials ( username , password ) ) ;
141
144
}
142
145
143
146
await rdpConnector . Connect ( domainName , ct : ct ) ;
144
147
}
145
-
146
- public ValueTask DisposeAsync ( )
147
- {
148
- return ValueTask . CompletedTask ;
149
- }
150
148
}
0 commit comments