@@ -783,6 +783,11 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
783
783
} ) ;
784
784
}
785
785
786
+ public async getRemoteExecServer ( remoteAuthority : string ) : Promise < vscode . ExecServer | undefined > {
787
+ const { resolver } = await this . _activateAndGetResolver ( remoteAuthority ) ;
788
+ return resolver ?. resolveExecServer ?.( remoteAuthority , { resolveAttempt : 0 } ) ;
789
+ }
790
+
786
791
// -- called by main thread
787
792
788
793
private async _activateAndGetResolver ( remoteAuthority : string ) : Promise < { authorityPrefix : string ; resolver : vscode . RemoteAuthorityResolver | undefined } > {
@@ -798,99 +803,122 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
798
803
return { authorityPrefix, resolver : this . _resolvers [ authorityPrefix ] } ;
799
804
}
800
805
801
- public async $resolveAuthority ( remoteAuthority : string , resolveAttempt : number ) : Promise < Dto < IResolveAuthorityResult > > {
806
+ public async $resolveAuthority ( remoteAuthorityChain : string , resolveAttempt : number ) : Promise < Dto < IResolveAuthorityResult > > {
802
807
const sw = StopWatch . create ( false ) ;
803
- const prefix = ( ) => `[resolveAuthority(${ getRemoteAuthorityPrefix ( remoteAuthority ) } ,${ resolveAttempt } )][${ sw . elapsed ( ) } ms] ` ;
808
+ const prefix = ( ) => `[resolveAuthority(${ getRemoteAuthorityPrefix ( remoteAuthorityChain ) } ,${ resolveAttempt } )][${ sw . elapsed ( ) } ms] ` ;
804
809
const logInfo = ( msg : string ) => this . _logService . info ( `${ prefix ( ) } ${ msg } ` ) ;
805
810
const logError = ( msg : string , err : any = undefined ) => this . _logService . error ( `${ prefix ( ) } ${ msg } ` , err ) ;
811
+ const normalizeError = ( err : unknown ) => {
812
+ if ( err instanceof RemoteAuthorityResolverError ) {
813
+ return {
814
+ type : 'error' as const ,
815
+ error : {
816
+ code : err . _code ,
817
+ message : err . _message ,
818
+ detail : err . _detail
819
+ }
820
+ } ;
821
+ }
822
+ throw err ;
823
+ } ;
806
824
807
- logInfo ( `activating resolver...` ) ;
808
- const { authorityPrefix, resolver } = await this . _activateAndGetResolver ( remoteAuthority ) ;
809
- if ( ! resolver ) {
810
- logError ( `no resolver` ) ;
811
- return {
812
- type : 'error' ,
813
- error : {
814
- code : RemoteAuthorityResolverErrorCode . NoResolverFound ,
815
- message : `No remote extension installed to resolve ${ authorityPrefix } .` ,
816
- detail : undefined
825
+ const chain = remoteAuthorityChain . split ( / @ | % 4 0 / g) . reverse ( ) ;
826
+ logInfo ( `activating remote resolvers ${ chain . join ( ' -> ' ) } ` ) ;
827
+
828
+ let resolvers ;
829
+ try {
830
+ resolvers = await Promise . all ( chain . map ( async remoteAuthority => {
831
+ logInfo ( `activating resolver...` ) ;
832
+ const { resolver, authorityPrefix } = await this . _activateAndGetResolver ( remoteAuthority ) ;
833
+ if ( ! resolver ) {
834
+ logError ( `no resolver` ) ;
835
+ throw new RemoteAuthorityResolverError ( `No remote extension installed to resolve ${ authorityPrefix } .` , RemoteAuthorityResolverErrorCode . NoResolverFound ) ;
817
836
}
818
- } ;
837
+ return { resolver, authorityPrefix, remoteAuthority } ;
838
+ } ) ) ;
839
+ } catch ( e ) {
840
+ return normalizeError ( e ) ;
819
841
}
820
842
821
843
const intervalLogger = new IntervalTimer ( ) ;
822
- try {
823
- logInfo ( `setting tunnel factory...` ) ;
824
- this . _register ( await this . _extHostTunnelService . setTunnelFactory ( resolver ) ) ;
825
-
826
- intervalLogger . cancelAndSet ( ( ) => logInfo ( 'waiting...' ) , 1000 ) ;
827
- logInfo ( `invoking resolve()...` ) ;
828
- performance . mark ( `code/extHost/willResolveAuthority/${ authorityPrefix } ` ) ;
829
- const result = await resolver . resolve ( remoteAuthority , { resolveAttempt } ) ;
830
- performance . mark ( `code/extHost/didResolveAuthorityOK/${ authorityPrefix } ` ) ;
831
- intervalLogger . dispose ( ) ;
832
-
833
- const tunnelInformation : TunnelInformation = {
834
- environmentTunnels : result . environmentTunnels ,
835
- features : result . tunnelFeatures
836
- } ;
844
+ intervalLogger . cancelAndSet ( ( ) => logInfo ( 'waiting...' ) , 1000 ) ;
837
845
838
- // Split merged API result into separate authority/options
839
- const options : ResolvedOptions = {
840
- extensionHostEnv : result . extensionHostEnv ,
841
- isTrusted : result . isTrusted ,
842
- authenticationSession : result . authenticationSessionForInitializingExtensions ? { id : result . authenticationSessionForInitializingExtensions . id , providerId : result . authenticationSessionForInitializingExtensions . providerId } : undefined
843
- } ;
846
+ let result ! : vscode . ResolverResult ;
847
+ let execServer : vscode . ExecServer | undefined ;
848
+ for ( const [ i , { authorityPrefix, resolver, remoteAuthority } ] of resolvers . entries ( ) ) {
849
+ try {
850
+ if ( i === resolvers . length - 1 ) {
851
+ logInfo ( `invoking final resolve()...` ) ;
852
+ performance . mark ( `code/extHost/willResolveAuthority/${ authorityPrefix } ` ) ;
853
+ result = await resolver . resolve ( remoteAuthority , { resolveAttempt, execServer } ) ;
854
+ performance . mark ( `code/extHost/didResolveAuthorityOK/${ authorityPrefix } ` ) ;
855
+ // todo@connor 4312: we probably need to chain tunnels too, how does this work with 'public' tunnels?
856
+ logInfo ( `setting tunnel factory...` ) ;
857
+ this . _register ( await this . _extHostTunnelService . setTunnelFactory ( resolver ) ) ;
858
+ } else {
859
+ logInfo ( `invoking resolveExecServer() for ${ remoteAuthority } ` ) ;
860
+ performance . mark ( `code/extHost/willResolveExecServer/${ authorityPrefix } ` ) ;
861
+ execServer = await resolver . resolveExecServer ?.( remoteAuthority , { resolveAttempt, execServer } ) ;
862
+ if ( ! execServer ) {
863
+ throw new RemoteAuthorityResolverError ( `Exec server was not available for ${ remoteAuthority } ` , RemoteAuthorityResolverErrorCode . NoResolverFound ) ; // we did, in fact, break the chain :(
864
+ }
865
+ performance . mark ( `code/extHost/didResolveExecServerOK/${ authorityPrefix } ` ) ;
866
+ }
867
+ } catch ( e ) {
868
+ performance . mark ( `code/extHost/didResolveAuthorityError/${ authorityPrefix } ` ) ;
869
+ logError ( `returned an error` , e ) ;
870
+ intervalLogger . dispose ( ) ;
871
+ return normalizeError ( e ) ;
872
+ }
873
+ }
844
874
845
- // extension are not required to return an instance of ResolvedAuthority or ManagedResolvedAuthority, so don't use `instanceof`
846
- logInfo ( `returned ${ ExtHostManagedResolvedAuthority . isManagedResolvedAuthority ( result ) ? 'managed authority' : `${ result . host } :${ result . port } ` } ` ) ;
875
+ intervalLogger . dispose ( ) ;
847
876
848
- let authority : ResolvedAuthority ;
849
- if ( ExtHostManagedResolvedAuthority . isManagedResolvedAuthority ( result ) ) {
850
- // The socket factory is identified by the `resolveAttempt`, since that is a number which
851
- // always increments and is unique over all resolve() calls in a workbench session.
852
- const socketFactoryId = resolveAttempt ;
877
+ const tunnelInformation : TunnelInformation = {
878
+ environmentTunnels : result . environmentTunnels ,
879
+ features : result . tunnelFeatures
880
+ } ;
853
881
854
- // There is only on managed socket factory at a time, so we can just overwrite the old one.
855
- this . _extHostManagedSockets . setFactory ( socketFactoryId , result . makeConnection ) ;
882
+ // Split merged API result into separate authority/options
883
+ const options : ResolvedOptions = {
884
+ extensionHostEnv : result . extensionHostEnv ,
885
+ isTrusted : result . isTrusted ,
886
+ authenticationSession : result . authenticationSessionForInitializingExtensions ? { id : result . authenticationSessionForInitializingExtensions . id , providerId : result . authenticationSessionForInitializingExtensions . providerId } : undefined
887
+ } ;
856
888
857
- authority = {
858
- authority : remoteAuthority ,
859
- connectTo : new ManagedRemoteConnection ( socketFactoryId ) ,
860
- connectionToken : result . connectionToken
861
- } ;
862
- } else {
863
- authority = {
864
- authority : remoteAuthority ,
865
- connectTo : new WebSocketRemoteConnection ( result . host , result . port ) ,
866
- connectionToken : result . connectionToken
867
- } ;
868
- }
889
+ // extension are not required to return an instance of ResolvedAuthority or ManagedResolvedAuthority, so don't use `instanceof`
890
+ logInfo ( `returned ${ ExtHostManagedResolvedAuthority . isManagedResolvedAuthority ( result ) ? 'managed authority' : `${ result . host } :${ result . port } ` } ` ) ;
869
891
870
- return {
871
- type : 'ok' ,
872
- value : {
873
- authority : authority as Dto < ResolvedAuthority > ,
874
- options,
875
- tunnelInformation,
876
- }
892
+ let authority : ResolvedAuthority ;
893
+ if ( ExtHostManagedResolvedAuthority . isManagedResolvedAuthority ( result ) ) {
894
+ // The socket factory is identified by the `resolveAttempt`, since that is a number which
895
+ // always increments and is unique over all resolve() calls in a workbench session.
896
+ const socketFactoryId = resolveAttempt ;
897
+
898
+ // There is only on managed socket factory at a time, so we can just overwrite the old one.
899
+ this . _extHostManagedSockets . setFactory ( socketFactoryId , result . makeConnection ) ;
900
+
901
+ authority = {
902
+ authority : remoteAuthorityChain ,
903
+ connectTo : new ManagedRemoteConnection ( socketFactoryId ) ,
904
+ connectionToken : result . connectionToken
905
+ } ;
906
+ } else {
907
+ authority = {
908
+ authority : remoteAuthorityChain ,
909
+ connectTo : new WebSocketRemoteConnection ( result . host , result . port ) ,
910
+ connectionToken : result . connectionToken
877
911
} ;
878
- } catch ( err ) {
879
- performance . mark ( `code/extHost/didResolveAuthorityError/${ authorityPrefix } ` ) ;
880
- intervalLogger . dispose ( ) ;
881
- logError ( `returned an error` , err ) ;
882
- if ( err instanceof RemoteAuthorityResolverError ) {
883
- return {
884
- type : 'error' ,
885
- error : {
886
- code : err . _code ,
887
- message : err . _message ,
888
- detail : err . _detail
889
- }
890
- } ;
891
- }
892
- throw err ;
893
912
}
913
+
914
+ return {
915
+ type : 'ok' ,
916
+ value : {
917
+ authority : authority as Dto < ResolvedAuthority > ,
918
+ options,
919
+ tunnelInformation,
920
+ }
921
+ } ;
894
922
}
895
923
896
924
public async $getCanonicalURI ( remoteAuthority : string , uriComponents : UriComponents ) : Promise < UriComponents | null > {
@@ -1047,6 +1075,7 @@ export interface IExtHostExtensionService extends AbstractExtHostExtensionServic
1047
1075
getExtensionRegistry ( ) : Promise < ExtensionDescriptionRegistry > ;
1048
1076
getExtensionPathIndex ( ) : Promise < ExtensionPaths > ;
1049
1077
registerRemoteAuthorityResolver ( authorityPrefix : string , resolver : vscode . RemoteAuthorityResolver ) : vscode . Disposable ;
1078
+ getRemoteExecServer ( authority : string ) : Promise < vscode . ExecServer | undefined > ;
1050
1079
1051
1080
onDidChangeRemoteConnectionData : Event < void > ;
1052
1081
getRemoteConnectionData ( ) : IRemoteConnectionData | null ;
0 commit comments