1
1
import Foundation
2
+ import SwiftUI
2
3
import URLRouting
3
4
4
5
@MainActor
@@ -20,20 +21,65 @@ class URLHandler {
20
21
guard deployment. host ( ) == url. host else {
21
22
throw . invalidAuthority( url. host ( ) ?? " <none> " )
22
23
}
24
+ let route : CoderRoute
23
25
do {
24
- switch try router. match ( url: url) {
25
- case let . open( workspace, agent, type) :
26
- switch type {
27
- case let . rdp( creds) :
28
- handleRDP ( workspace: workspace, agent: agent, creds: creds)
29
- }
30
- }
26
+ route = try router. match ( url: url)
31
27
} catch {
32
28
throw . routerError( url: url)
33
29
}
34
30
35
- func handleRDP( workspace _: String , agent _: String , creds _: RDPCredentials ) {
36
- // TODO: Handle RDP
31
+ switch route {
32
+ case let . open( workspace, agent, type) :
33
+ switch type {
34
+ case let . rdp( creds) :
35
+ try handleRDP ( workspace: workspace, agent: agent, creds: creds)
36
+ }
37
+ }
38
+ }
39
+
40
+ private func handleRDP( workspace: String , agent: String , creds: RDPCredentials ) throws ( URLError) {
41
+ guard vpn. state == . connected else {
42
+ throw . openError( . coderConnectOffline)
43
+ }
44
+
45
+ guard let workspace = vpn. menuState. findWorkspace ( name: workspace) else {
46
+ throw . openError( . invalidWorkspace( workspace: workspace) )
47
+ }
48
+
49
+ guard let agent = vpn. menuState. findAgent ( workspaceID: workspace. id, name: agent) else {
50
+ throw . openError( . invalidAgent( workspace: workspace. name, agent: agent) )
51
+ }
52
+
53
+ var rdpString = " rdp:full address=s: \( agent. primaryHost) :3389 "
54
+ if let username = creds. username {
55
+ rdpString += " &username=s: \( username) "
56
+ }
57
+ guard let url = URL ( string: rdpString) else {
58
+ throw . openError( . couldNotCreateRDPURL( rdpString) )
59
+ }
60
+
61
+ let alert = NSAlert ( )
62
+ alert. messageText = " Opening RDP "
63
+ alert. informativeText = " Connecting to \( agent. primaryHost) . "
64
+ if let username = creds. username {
65
+ alert. informativeText += " \n Username: \( username) "
66
+ }
67
+ if creds. password != nil {
68
+ alert. informativeText += " \n The password will be copied to your clipboard. "
69
+ }
70
+
71
+ alert. alertStyle = . informational
72
+ alert. addButton ( withTitle: " Open " )
73
+ alert. addButton ( withTitle: " Cancel " )
74
+ let response = alert. runModal ( )
75
+ if response == . alertFirstButtonReturn {
76
+ if let password = creds. password {
77
+ NSPasteboard . general. clearContents ( )
78
+ NSPasteboard . general. setString ( password, forType: . string)
79
+ }
80
+ NSWorkspace . shared. open ( url)
81
+ } else {
82
+ // User cancelled
37
83
}
38
84
}
39
85
}
@@ -66,6 +112,7 @@ enum URLError: Error {
66
112
case invalidAuthority( String )
67
113
case routerError( url: URL )
68
114
case noSession
115
+ case openError( OpenError )
69
116
70
117
var description : String {
71
118
switch self {
@@ -75,6 +122,30 @@ enum URLError: Error {
75
122
" Failed to handle \( url. absoluteString) because the format is unsupported. "
76
123
case . noSession:
77
124
" Not logged in. "
125
+ case let . openError( error) :
126
+ error. description
127
+ }
128
+ }
129
+
130
+ var localizedDescription : String { description }
131
+ }
132
+
133
+ enum OpenError : Error {
134
+ case invalidWorkspace( workspace: String )
135
+ case invalidAgent( workspace: String , agent: String )
136
+ case coderConnectOffline
137
+ case couldNotCreateRDPURL( String )
138
+
139
+ var description : String {
140
+ switch self {
141
+ case let . invalidWorkspace( ws) :
142
+ " Could not find workspace ' \( ws) '. Does it exist? "
143
+ case . coderConnectOffline:
144
+ " Coder Connect must be running. "
145
+ case let . invalidAgent( workspace: workspace, agent: agent) :
146
+ " Could not find agent ' \( agent) ' in workspace ' \( workspace) '. Is the workspace running? "
147
+ case let . couldNotCreateRDPURL( rdpString) :
148
+ " Could not create construct RDP url from ' \( rdpString) '. "
78
149
}
79
150
}
80
151
0 commit comments