提交 bbf251e4 编写于 作者: H Heejae Chang

added service hub component and setup project for service hub

service hub component is basically thin layer that deals with converting data to pass in to RemoteWorkspace
上级 7e05de87
......@@ -24,6 +24,7 @@
<add key="myget.org symreader" value="https://dotnet.myget.org/F/symreader/api/v3/index.json" />
<add key="myget.org symreader-portable" value="https://dotnet.myget.org/F/symreader-portable/api/v3/index.json" />
<add key="myget.org roslyn-master-nightly" value="https://dotnet.myget.org/F/roslyn-master-nightly/api/v3/index.json" />
<add key="myget.org devcore" value="https://www.myget.org/F/vs-devcore/api/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
......
......@@ -374,6 +374,12 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Meta
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.PooledObjects", "src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.shproj", "{C1930979-C824-496B-A630-70F5369A636F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicesVisualStudio.Next", "src\VisualStudio\Next\ServicesVisualStudio.Next.csproj", "{FE0D4BDD-1C30-488E-A870-854F5B8C5014}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteWorkspaces", "src\Workspaces\Remote\Core\RemoteWorkspaces.csproj", "{F822F72A-CC87-4E31-B57D-853F65CBEBF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceHub", "src\Workspaces\Remote\ServiceHub\ServiceHub.csproj", "{80FDDD00-9393-47F7-8BAF-7E87CE011068}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Compilers\Core\CommandLine\CommandLine.projitems*{06b26dcb-7a12-48ef-ae50-708593abd05f}*SharedItemsImports = 4
......@@ -3205,6 +3211,66 @@ Global
{3DA711E1-055F-4352-A5E1-F9169C86A20F}.Release|x64.Build.0 = Release|Any CPU
{3DA711E1-055F-4352-A5E1-F9169C86A20F}.Release|x86.ActiveCfg = Release|Any CPU
{3DA711E1-055F-4352-A5E1-F9169C86A20F}.Release|x86.Build.0 = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|ARM.ActiveCfg = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|ARM.Build.0 = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x64.ActiveCfg = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x64.Build.0 = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x86.ActiveCfg = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x86.Build.0 = Debug|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Any CPU.Build.0 = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|ARM.ActiveCfg = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|ARM.Build.0 = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x64.ActiveCfg = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x64.Build.0 = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x86.ActiveCfg = Release|Any CPU
{FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x86.Build.0 = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|ARM.ActiveCfg = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|ARM.Build.0 = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x64.ActiveCfg = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x64.Build.0 = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x86.ActiveCfg = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x86.Build.0 = Debug|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Any CPU.Build.0 = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|ARM.ActiveCfg = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|ARM.Build.0 = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x64.ActiveCfg = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x64.Build.0 = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x86.ActiveCfg = Release|Any CPU
{F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x86.Build.0 = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|ARM.ActiveCfg = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|ARM.Build.0 = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x64.ActiveCfg = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x64.Build.0 = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x86.ActiveCfg = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x86.Build.0 = Debug|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Any CPU.Build.0 = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|ARM.ActiveCfg = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|ARM.Build.0 = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x64.ActiveCfg = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x64.Build.0 = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x86.ActiveCfg = Release|Any CPU
{80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -3376,5 +3442,8 @@ Global
{3DA711E1-055F-4352-A5E1-F9169C86A20F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{D73ADF7D-2C1C-42AE-B2AB-EDC9497E4B71} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{C1930979-C824-496B-A630-70F5369A636F} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{FE0D4BDD-1C30-488E-A870-854F5B8C5014} = {8DBA5174-B0AA-4561-82B1-A46607697753}
{F822F72A-CC87-4E31-B57D-853F65CBEBF3} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5}
{80FDDD00-9393-47F7-8BAF-7E87CE011068} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5}
EndGlobalSection
EndGlobal
......@@ -23,6 +23,8 @@
"Microsoft.CodeAnalysis.Features.dll",
"Microsoft.CodeAnalysis.InteractiveEditorFeatures.dll",
"Microsoft.CodeAnalysis.InteractiveFeatures.dll",
"Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
"Microsoft.CodeAnalysis.Remote.Workspaces.dll",
"Microsoft.CodeAnalysis.Scripting.dll",
"Microsoft.CodeAnalysis.VisualBasic.dll",
"Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.dll",
......@@ -39,6 +41,7 @@
"Microsoft.VisualStudio.LanguageServices.CSharp.dll",
"Microsoft.VisualStudio.LanguageServices.dll",
"Microsoft.VisualStudio.LanguageServices.Implementation.dll",
"Microsoft.VisualStudio.LanguageServices.Next.dll",
"Microsoft.VisualStudio.LanguageServices.SolutionExplorer.dll",
"Microsoft.VisualStudio.LanguageServices.VisualBasic.dll",
"Microsoft.VisualStudio.VisualBasic.Repl.dll",
......@@ -108,6 +111,9 @@
"Microsoft.DiaSymReader.dll",
"Microsoft.DiaSymReader.Native.amd64.dll",
"Microsoft.DiaSymReader.Native.x86.dll",
"Newtonsoft.Json.dll",
"StreamJsonRpc.dll",
"StreamJsonRpc.resources.dll",
"System.Reflection.Metadata.dll",
"System.Collections.Immutable.dll",
"System.Diagnostics.StackTrace.dll",
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.EngineV2;
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Implementation.Remote;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Diagnostics
{
[ExportWorkspaceService(typeof(ICompilerDiagnosticAnalyzer), layer: ServiceLayer.Host), Shared]
internal class OutOfProcCompilerDiagnosticAnalyzer : ICompilerDiagnosticAnalyzer
{
private static readonly ICompilerDiagnosticAnalyzer _inProcAnalyzer = new InProcCompilerDiagnosticAnalyzer();
private readonly IDiagnosticAnalyzerService _analyzerService;
private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSource;
// TODO: solution snapshot tracking for current solution should be its own service
private ChecksumScope _lastSnapshot;
[ImportingConstructor]
public OutOfProcCompilerDiagnosticAnalyzer(
IDiagnosticAnalyzerService analyzerService,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
{
_analyzerService = analyzerService;
_hostDiagnosticUpdateSource = hostDiagnosticUpdateSource;
}
public async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
var remoteHostClient = await project.Solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false);
}
// TODO: later, make sure we can run all analyzer on remote host.
// for now, we will check whether built in analyzer can run on remote host and only those run on remote host.
var inProcResultTask = AnalyzeInProcAsync(CreateAnalyzerDriver(analyzerDriver, a => a.MustRunInProc()), project, cancellationToken);
var outOfProcResultTask = AnalyzeOutOfProcAsync(remoteHostClient, analyzerDriver, project, cancellationToken);
// run them concurrently in vs and remote host
await Task.WhenAll(inProcResultTask, outOfProcResultTask).ConfigureAwait(false);
// make sure things are not cancelled
cancellationToken.ThrowIfCancellationRequested();
// merge 2 results
return DiagnosticAnalysisResultMap.Create(
inProcResultTask.Result.AnalysisResult.AddRange(outOfProcResultTask.Result.AnalysisResult),
inProcResultTask.Result.TelemetryInfo.AddRange(outOfProcResultTask.Result.TelemetryInfo));
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeInProcAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
return await _inProcAnalyzer.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false);
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeOutOfProcAsync(
RemoteHostClient client, CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
var solution = project.Solution;
var snapshotService = solution.Workspace.Services.GetService<ISolutionChecksumService>();
// TODO: incremental build of solution snapshot should be its own service
await UpdateLastSolutionSnapshotAsync(snapshotService, solution).ConfigureAwait(false);
// TODO: this should be moved out
var hostChecksums = GetHostAnalyzerReferences(snapshotService, _analyzerService.GetHostAnalyzerReferences(), cancellationToken);
var analyzerMap = CreateAnalyzerMap(analyzerDriver.Analyzers.Where(a => !a.MustRunInProc()));
if (analyzerMap.Count == 0)
{
return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.Empty);
}
// TODO: send telemetry on session
using (var session = await client.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
var argument = new DiagnosticArguments(
analyzerDriver.AnalysisOptions.ReportSuppressedDiagnostics,
analyzerDriver.AnalysisOptions.LogAnalyzerExecutionTime,
project.Id, hostChecksums, analyzerMap.Keys.ToArray());
var result = await session.InvokeAsync(
WellKnownServiceHubServices.CodeAnalysisService_CalculateDiagnosticsAsync,
new object[] { argument },
(s, c) => GetCompilerAnalysisResultAsync(s, analyzerMap, project, c)).ConfigureAwait(false);
ReportAnalyzerExceptions(project, result.Exceptions);
return result;
}
}
private async Task UpdateLastSolutionSnapshotAsync(ISolutionChecksumService snapshotService, Solution solution)
{
// TODO: actual incremental build of solution snapshot should be its own service
// this is needed to make sure we incrementally update solution checksums. otherwise, we will always create from
// scratch which can be quite expansive for big solution
var lastSnapshot = _lastSnapshot;
_lastSnapshot = await snapshotService.CreateChecksumAsync(solution, CancellationToken.None).ConfigureAwait(false);
lastSnapshot?.Dispose();
}
private CompilationWithAnalyzers CreateAnalyzerDriver(CompilationWithAnalyzers analyzerDriver, Func<DiagnosticAnalyzer, bool> predicate)
{
var analyzers = analyzerDriver.Analyzers.Where(predicate).ToImmutableArray();
return analyzerDriver.Compilation.WithAnalyzers(analyzers, analyzerDriver.AnalysisOptions);
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> GetCompilerAnalysisResultAsync(Stream stream, Dictionary<string, DiagnosticAnalyzer> analyzerMap, Project project, CancellationToken cancellationToken)
{
// handling of cancellation and exception
var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);
using (var reader = new ObjectReader(stream))
{
return DiagnosticResultSerializer.Deserialize(reader, analyzerMap, project, version, cancellationToken);
}
}
private void ReportAnalyzerExceptions(Project project, ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<DiagnosticData>> exceptions)
{
foreach (var kv in exceptions)
{
var analyzer = kv.Key;
foreach (var diagnostic in kv.Value)
{
_hostDiagnosticUpdateSource.ReportAnalyzerDiagnostic(analyzer, diagnostic, project);
}
}
}
private ImmutableArray<byte[]> GetHostAnalyzerReferences(ISolutionChecksumService snapshotService, IEnumerable<AnalyzerReference> references, CancellationToken cancellationToken)
{
// TODO: cache this to somewhere
var builder = ImmutableArray.CreateBuilder<byte[]>();
foreach (var reference in references)
{
var asset = snapshotService.GetGlobalAsset(reference, cancellationToken);
builder.Add(asset.Checksum.ToArray());
}
return builder.ToImmutable();
}
private Dictionary<string, DiagnosticAnalyzer> CreateAnalyzerMap(IEnumerable<DiagnosticAnalyzer> analyzers)
{
// TODO: this needs to be cached. we can have 300+ analyzers
return analyzers.ToDictionary(a => a.GetAnalyzerIdAndVersion().Item1, a => a);
}
}
}
......@@ -12,3 +12,7 @@
OldVersionLowerBound = "14.0.0.0",
OldVersionUpperBound = "14.9.9.9",
NewVersion = "15.0.0.0")]
[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\StreamJsonRpc.dll")]
[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.ServiceHub.Client.dll")]
[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Newtonsoft.Json.dll")]
\ No newline at end of file
......@@ -24,6 +24,24 @@
<DeployExtension Condition="'$(VisualStudioVersion)' == '14.0'">false</DeployExtension>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\..\Compilers\Core\Portable\CodeAnalysis.csproj">
<Project>{1ee8cad3-55f9-4d91-96b2-084641da9a6c}</Project>
<Name>CodeAnalysis</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Compilers\CSharp\Portable\CSharpCodeAnalysis.csproj">
<Project>{b501a547-c911-4a05-ac6e-274a50dff30e}</Project>
<Name>CSharpCodeAnalysis</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Compilers\VisualBasic\Portable\BasicCodeAnalysis.vbproj">
<Project>{2523d0e6-df32-4a3e-8ae0-a19bffae2ef6}</Project>
<Name>BasicCodeAnalysis</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Dependencies\VisualStudio\VisualStudio.csproj">
<Project>{8da861d8-0cce-4334-b6c0-01a846c881ec}</Project>
<Name>VisualStudio</Name>
......@@ -35,12 +53,62 @@
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<IncludeOutputGroupsInVSIXLocalOnly>DebugSymbolsProjectOutputGroup%3b</IncludeOutputGroupsInVSIXLocalOnly>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\Core\Desktop\Workspaces.Desktop.csproj">
<Project>{2e87fa96-50bb-4607-8676-46521599f998}</Project>
<Name>Workspaces.Desktop</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\Core\Portable\Workspaces.csproj">
<Project>{5f8d2414-064a-4b3a-9b42-8e2a04246be5}</Project>
<Name>Workspaces</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\CSharp\Portable\CSharpWorkspace.csproj">
<Project>{21b239d0-d144-430f-a394-c066d58ee267}</Project>
<Name>CSharpWorkspace</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\Remote\Core\RemoteWorkspaces.csproj">
<Project>{f822f72a-cc87-4e31-b57d-853f65cbebf3}</Project>
<Name>RemoteWorkspaces</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\Remote\ServiceHub\ServiceHub.csproj">
<Project>{80fddd00-9393-47f7-8baf-7e87ce011068}</Project>
<Name>ServiceHub</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\..\Workspaces\VisualBasic\Portable\BasicWorkspace.vbproj">
<Project>{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}</Project>
<Name>BasicWorkspace</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\Next\ServicesVisualStudio.Next.csproj">
<Project>{fe0d4bdd-1c30-488e-a870-854f5b8c5014}</Project>
<Name>ServicesVisualStudio.Next</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
<ForceIncludeInVSIX>true</ForceIncludeInVSIX>
</ProjectReference>
<ProjectReference Include="..\Setup\VisualStudioSetup.csproj">
<Name>VisualStudioSetup</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<NuGetPackageToIncludeInVsix Include="StreamJsonRpc" />
<NuGetPackageToIncludeInVsix Include="Newtonsoft.Json" />
<!-- Visual Studio ships with some, but not all, of the assemblies in Microsoft.Composition, but we need them all -->
<NuGetPackageToIncludeInVsix Include="Microsoft.Composition" />
<NuGetPackageToIncludeInVsix Include="System.Reflection.Metadata" />
<NuGetPackageToIncludeInVsix Include="System.Collections.Immutable" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
......@@ -53,7 +121,19 @@
<StartArguments>/rootsuffix RoslynDev /log</StartArguments>
</PropertyGroup>
<ItemGroup>
<Content Include="serviceHubSnapshotService.servicehub.service.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<None Include="project.json" />
<Content Include="codeAnalysisService.servicehub.service.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<Content Include="remoteHostService.servicehub.service.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
......
{
"$schema": "../../../schemas/servicehub.service.schema.json",
"host": "desktopClr.x86",
"hostId": "RoslynCodeAnalysisService32",
"entryPoint": {
"assemblyPath": "Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
"fullClassName": "Microsoft.CodeAnalysis.Remote.CodeAnalysisService"
}
}
\ No newline at end of file
{
"dependencies": {
"StreamJsonRpc": "0.14.3-alpha",
"Newtonsoft.Json": "6.0.6"
},
"frameworks": {
"net46": { }
......
{
"$schema": "../../../schemas/servicehub.service.schema.json",
"host": "desktopClr.x86",
"hostId": "RoslynCodeAnalysisService32",
"entryPoint": {
"assemblyPath": "Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
"fullClassName": "Microsoft.CodeAnalysis.Remote.RemoteHostService"
}
}
\ No newline at end of file
{
"$schema": "../../../schemas/servicehub.service.schema.json",
"host": "desktopClr.x86",
"hostId": "RoslynCodeAnalysisService32",
"entryPoint": {
"assemblyPath": "Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
"fullClassName": "Microsoft.CodeAnalysis.Remote.ServiceHubSnapshotService"
}
}
\ No newline at end of file
......@@ -17,5 +17,9 @@
</Dependencies>
<Assets>
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="EditorFeatures.Next" Path="|EditorFeatures.Next|" />
<Asset Type="Microsoft.ServiceHub.Service" d:Source="File" Path="remoteHostService.servicehub.service.json" />
<Asset Type="Microsoft.ServiceHub.Service" d:Source="File" Path="serviceHubSnapshotService.servicehub.service.json" />
<Asset Type="Microsoft.ServiceHub.Service" d:Source="File" Path="codeAnalysisService.servicehub.service.json" />
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="ServicesVisualStudio.Next" Path="|ServicesVisualStudio.Next|" />
</Assets>
</PackageManifest>
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Execution;
namespace Microsoft.CodeAnalysis.Remote.Diagnostics
{
/// <summary>
/// helper type to package diagnostic arguments to pass around between remote hosts
/// </summary>
internal class DiagnosticArguments
{
public bool ReportSuppressedDiagnostics;
public bool LogAnalyzerExecutionTime;
public Guid ProjectIdGuid;
public string ProjectIdDebugName;
public byte[][] HostAnalyzerChecksumsByteArray;
public string[] AnalyzerIds;
public DiagnosticArguments()
{
}
public DiagnosticArguments(
bool reportSuppressedDiagnostics,
bool logAnalyzerExecutionTime,
ProjectId projectId,
ImmutableArray<byte[]> hostAnalyzerChecksums,
string[] analyzerIds)
{
ReportSuppressedDiagnostics = reportSuppressedDiagnostics;
LogAnalyzerExecutionTime = logAnalyzerExecutionTime;
ProjectIdGuid = projectId.Id;
ProjectIdDebugName = projectId.DebugName;
HostAnalyzerChecksumsByteArray = hostAnalyzerChecksums.ToArray();
AnalyzerIds = analyzerIds;
}
public ProjectId GetProjectId() => ProjectId.CreateFromSerialized(ProjectIdGuid, ProjectIdDebugName);
public IEnumerable<Checksum> GetHostAnalyzerChecksums() => HostAnalyzerChecksumsByteArray.Select(b => new Checksum(b));
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Remote.Diagnostics
{
internal static class DiagnosticResultSerializer
{
public static void Serialize(ObjectWriter writer, DiagnosticAnalysisResultMap<string, DiagnosticAnalysisResultBuilder> result, CancellationToken cancellationToken)
{
var diagnosticSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);
var analysisResult = result.AnalysisResult;
writer.WriteInt32(analysisResult.Count);
foreach (var kv in analysisResult)
{
writer.WriteString(kv.Key);
Serialize(writer, diagnosticSerializer, kv.Value.SyntaxLocals, cancellationToken);
Serialize(writer, diagnosticSerializer, kv.Value.SemanticLocals, cancellationToken);
Serialize(writer, diagnosticSerializer, kv.Value.NonLocals, cancellationToken);
diagnosticSerializer.WriteTo(writer, kv.Value.Others, cancellationToken);
}
var telemetryInfo = result.TelemetryInfo;
writer.WriteInt32(telemetryInfo.Count);
foreach (var kv in telemetryInfo)
{
writer.WriteString(kv.Key);
Serialize(writer, kv.Value, cancellationToken);
}
var exceptions = result.Exceptions;
writer.WriteInt32(exceptions.Count);
foreach (var kv in exceptions)
{
writer.WriteString(kv.Key);
diagnosticSerializer.WriteTo(writer, kv.Value, cancellationToken);
}
}
public static DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult> Deserialize(
ObjectReader reader, IDictionary<string, DiagnosticAnalyzer> analyzerMap, Project project, VersionStamp version, CancellationToken cancellationToken)
{
var diagnosticDataSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);
var analysisMap = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, DiagnosticAnalysisResult>();
var analysisCount = reader.ReadInt32();
for (var i = 0; i < analysisCount; i++)
{
var analyzer = analyzerMap[reader.ReadString()];
var syntaxLocalMap = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
var semanticLocalMap = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
var nonLocalMap = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
var others = diagnosticDataSerializer.ReadFrom(reader, project, cancellationToken);
var analysisResult = new DiagnosticAnalysisResult(
project.Id, version,
syntaxLocalMap, semanticLocalMap, nonLocalMap, others,
documentIds: null, fromBuild: false);
analysisMap.Add(analyzer, analysisResult);
}
var telemetryMap = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, AnalyzerTelemetryInfo>();
var telemetryCount = reader.ReadInt32();
for (var i = 0; i < telemetryCount; i++)
{
var analyzer = analyzerMap[reader.ReadString()];
var telemetryInfo = Deserialize(reader, cancellationToken);
telemetryMap.Add(analyzer, telemetryInfo);
}
var exceptionMap = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, ImmutableArray<DiagnosticData>>();
var exceptionCount = reader.ReadInt32();
for (var i = 0; i < exceptionCount; i++)
{
var analyzer = analyzerMap[reader.ReadString()];
var exceptions = diagnosticDataSerializer.ReadFrom(reader, project, cancellationToken);
exceptionMap.Add(analyzer, exceptions);
}
return DiagnosticAnalysisResultMap.Create(analysisMap.ToImmutable(), telemetryMap.ToImmutable(), exceptionMap.ToImmutable());
}
private static void Serialize(
ObjectWriter writer,
DiagnosticDataSerializer serializer,
ImmutableDictionary<DocumentId, ImmutableArray<DiagnosticData>> diagnostics,
CancellationToken cancellationToken)
{
writer.WriteInt32(diagnostics.Count);
foreach (var kv in diagnostics)
{
Serializer.Serialize(kv.Key, writer, cancellationToken);
serializer.WriteTo(writer, kv.Value, cancellationToken);
}
}
private static ImmutableDictionary<DocumentId, ImmutableArray<DiagnosticData>> Deserialize(
ObjectReader reader,
DiagnosticDataSerializer serializer,
Project project,
CancellationToken cancellationToken)
{
var count = reader.ReadInt32();
var map = ImmutableDictionary.CreateBuilder<DocumentId, ImmutableArray<DiagnosticData>>();
for (var i = 0; i < count; i++)
{
var documentId = Serializer.DeserializeDocumentId(reader, cancellationToken);
var diagnostics = serializer.ReadFrom(reader, project.GetDocument(documentId), cancellationToken);
map.Add(documentId, diagnostics);
}
return map.ToImmutable();
}
private static void Serialize(ObjectWriter writer, AnalyzerTelemetryInfo telemetryInfo, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
writer.WriteInt32(telemetryInfo.CompilationStartActionsCount);
writer.WriteInt32(telemetryInfo.CompilationEndActionsCount);
writer.WriteInt32(telemetryInfo.CompilationActionsCount);
writer.WriteInt32(telemetryInfo.SyntaxTreeActionsCount);
writer.WriteInt32(telemetryInfo.SemanticModelActionsCount);
writer.WriteInt32(telemetryInfo.SymbolActionsCount);
writer.WriteInt32(telemetryInfo.SyntaxNodeActionsCount);
writer.WriteInt32(telemetryInfo.CodeBlockStartActionsCount);
writer.WriteInt32(telemetryInfo.CodeBlockEndActionsCount);
writer.WriteInt32(telemetryInfo.CodeBlockActionsCount);
writer.WriteInt32(telemetryInfo.OperationActionsCount);
writer.WriteInt32(telemetryInfo.OperationBlockActionsCount);
writer.WriteInt32(telemetryInfo.OperationBlockStartActionsCount);
writer.WriteInt32(telemetryInfo.OperationBlockEndActionsCount);
writer.WriteInt64(telemetryInfo.ExecutionTime.Ticks);
}
private static AnalyzerTelemetryInfo Deserialize(ObjectReader reader, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var compilationStartActionsCount = reader.ReadInt32();
var compilationEndActionsCount = reader.ReadInt32();
var compilationActionsCount = reader.ReadInt32();
var syntaxTreeActionsCount = reader.ReadInt32();
var semanticModelActionsCount = reader.ReadInt32();
var symbolActionsCount = reader.ReadInt32();
var syntaxNodeActionsCount = reader.ReadInt32();
var codeBlockStartActionsCount = reader.ReadInt32();
var codeBlockEndActionsCount = reader.ReadInt32();
var codeBlockActionsCount = reader.ReadInt32();
var operationActionsCount = reader.ReadInt32();
var operationBlockActionsCount = reader.ReadInt32();
var operationBlockStartActionsCount = reader.ReadInt32();
var operationBlockEndActionsCount = reader.ReadInt32();
var executionTime = new TimeSpan(reader.ReadInt64());
return new AnalyzerTelemetryInfo(
compilationStartActionsCount,
compilationEndActionsCount,
compilationActionsCount,
syntaxTreeActionsCount,
semanticModelActionsCount,
symbolActionsCount,
syntaxNodeActionsCount,
codeBlockStartActionsCount,
codeBlockEndActionsCount,
codeBlockActionsCount,
operationActionsCount,
operationBlockStartActionsCount,
operationBlockEndActionsCount,
operationBlockActionsCount,
executionTime);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectLanguage>CSharp</ProjectLanguage>
</PropertyGroup>
<ImportGroup Label="Settings">
<Import Project="..\..\..\..\build\Targets\VSL.Settings.targets" />
</ImportGroup>
<PropertyGroup>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">AnyCPU</Platform>
<ProjectGuid>{80FDDD00-9393-47F7-8BAF-7E87CE011068}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Microsoft.CodeAnalysis.Remote</RootNamespace>
<AssemblyName>Microsoft.CodeAnalysis.Remote.ServiceHub</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<CopyNuGetImplementations>false</CopyNuGetImplementations>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\..\..\Compilers\Core\Portable\CodeAnalysis.csproj">
<Project>{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}</Project>
<Name>CodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Dependencies\Immutable\Immutable.csproj">
<Project>{DCDA908D-EF5E-494B-ADDC-C26F5FD610CA}</Project>
<Name>Immutable</Name>
</ProjectReference>
<ProjectReference Include="..\..\Core\Desktop\Workspaces.Desktop.csproj">
<Project>{2e87fa96-50bb-4607-8676-46521599f998}</Project>
<Name>Workspaces.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\..\Core\Portable\Workspaces.csproj">
<Project>{5F8D2414-064A-4B3A-9B42-8E2A04246BE5}</Project>
<Name>Workspaces</Name>
</ProjectReference>
<ProjectReference Include="..\Core\RemoteWorkspaces.csproj">
<Project>{f822f72a-cc87-4e31-b57d-853f65cbebf3}</Project>
<Name>RemoteWorkspaces</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
<PublicAPI Include="PublicAPI.Shipped.txt" />
<PublicAPI Include="PublicAPI.Unshipped.txt" />
</ItemGroup>
<ItemGroup>
<Compile Include="Diagnostics\DiagnosticResultSerializer.cs" />
<Compile Include="Diagnostics\DiagnosticArguments.cs" />
<Compile Include="Services\CodeAnalysisService.cs" />
<Compile Include="Services\CodeAnalysisService_Diagnostics.cs" />
<Compile Include="Services\RemoteHostService.cs" />
<Compile Include="Services\ServiceHubJsonRpcServiceBase.cs" />
<Compile Include="Services\ServiceHubServiceBase.cs" />
<Compile Include="Services\ServiceHubSnapshotService.cs" />
<Compile Include="Shared\Extensions.cs" />
<Compile Include="Shared\ServerDirectStream.cs" />
<Compile Include="Shared\ClientDirectStream.cs" />
<Compile Include="Shared\WellKnownServiceHubServices.cs" />
</ItemGroup>
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
</Project>
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
namespace Microsoft.CodeAnalysis.Remote
{
// root level service for all Roslyn services
internal partial class CodeAnalysisService : ServiceHubJsonRpcServiceBase
{
public CodeAnalysisService(Stream stream, IServiceProvider serviceProvider) :
base(stream, serviceProvider)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Remote
{
// root level service for all Roslyn services
internal partial class CodeAnalysisService
{
/// <summary>
/// This is top level entry point for diagnostic calculation from client (VS).
///
/// This will be called by ServiceHub/JsonRpc framework
/// </summary>
public async Task CalculateDiagnosticsAsync(DiagnosticArguments arguments, byte[] solutionChecksum, string streamName)
{
try
{
// entry point for diagnostic service
var solution = await RoslynServices.SolutionService.GetSolutionAsync(new Checksum(solutionChecksum), CancellationToken).ConfigureAwait(false);
var projectId = arguments.GetProjectId();
var analyzers = await GetHostAnalyzerReferences(arguments.GetHostAnalyzerChecksums()).ConfigureAwait(false);
var result = await (new DiagnosticComputer(solution.GetProject(projectId))).GetDiagnosticsAsync(
analyzers, arguments.AnalyzerIds, arguments.ReportSuppressedDiagnostics, arguments.LogAnalyzerExecutionTime, CancellationToken).ConfigureAwait(false);
await SerializeDiagnosticResultAsync(streamName, result).ConfigureAwait(false);
}
catch (IOException)
{
// stream to send over result has closed before we
// had chance to check cancellation
}
catch (OperationCanceledException)
{
// rpc connection has closed.
// this can happen if client side cancelled the
// operation
}
}
private async Task<List<AnalyzerReference>> GetHostAnalyzerReferences(IEnumerable<Checksum> checksums)
{
var analyzers = new List<AnalyzerReference>();
foreach (var checksum in checksums)
{
analyzers.Add(await RoslynServices.AssetService.GetAssetAsync<AnalyzerReference>(checksum, CancellationToken).ConfigureAwait(false));
}
return analyzers;
}
private async Task SerializeDiagnosticResultAsync(string streamName, DiagnosticAnalysisResultMap<string, DiagnosticAnalysisResultBuilder> result)
{
using (var stream = new ClientDirectStream(streamName))
{
await stream.ConnectAsync(CancellationToken).ConfigureAwait(false);
using (var writer = new ObjectWriter(stream))
{
DiagnosticResultSerializer.Serialize(writer, result, CancellationToken);
}
await stream.FlushAsync(CancellationToken).ConfigureAwait(false);
// TODO: think of a way this is not needed
// wait for the other side to finish reading data I sent over
stream.WaitForServer();
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Threading;
namespace Microsoft.CodeAnalysis.Remote
{
/// <summary>
/// Service that client will connect to to make service hub alive even when there is
/// no other people calling service hub.
///
/// basically, this is used to manage lifetime of the service hub.
/// </summary>
internal class RemoteHostService : ServiceHubJsonRpcServiceBase
{
private string _host;
public RemoteHostService(Stream stream, IServiceProvider serviceProvider) :
base(stream, serviceProvider)
{
// this service provide a way for client to make sure remote host is alive
}
public string Connect(string host)
{
var existing = Interlocked.CompareExchange(ref _host, host, null);
if (existing != null && existing != host)
{
LogError($"{host} is given for {existing}");
}
return _host;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using StreamJsonRpc;
using System;
using System.IO;
using System.Threading;
namespace Microsoft.CodeAnalysis.Remote
{
internal abstract class ServiceHubJsonRpcServiceBase : ServiceHubServiceBase
{
private readonly CancellationTokenSource _source;
protected readonly JsonRpc Rpc;
protected readonly CancellationToken CancellationToken;
public ServiceHubJsonRpcServiceBase(Stream stream, IServiceProvider serviceProvider) : base(stream, serviceProvider)
{
_source = new CancellationTokenSource();
CancellationToken = _source.Token;
Rpc = JsonRpc.Attach(stream, this);
Rpc.Disconnected += OnRpcDisconnected;
}
protected virtual void OnDisconnected(JsonRpcDisconnectedEventArgs e)
{
// do nothing
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Rpc.Dispose();
}
private void OnRpcDisconnected(object sender, JsonRpcDisconnectedEventArgs e)
{
// raise cancellation
_source.Cancel();
OnDisconnected(e);
if (e.Reason != DisconnectedReason.Disposed)
{
LogError($"Client stream disconnected unexpectedly: {e.Exception?.GetType().Name} {e.Exception?.Message}");
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace Microsoft.CodeAnalysis.Remote
{
// TODO: all service hub service should be extract to interface so that it can support multiple hosts.
// right now, tightly coupled to service hub
internal abstract class ServiceHubServiceBase : IDisposable
{
private static int s_instanceId = 0;
protected readonly int InstanceId = 0;
protected readonly TraceSource Logger;
protected readonly Stream Stream;
protected ServiceHubServiceBase(Stream stream, IServiceProvider serviceProvider)
{
InstanceId = Interlocked.Add(ref s_instanceId, 1);
Logger = (TraceSource)serviceProvider.GetService(typeof(TraceSource));
Logger.TraceInformation($"{DebugInstanceString} Service instance created");
Stream = stream;
}
protected string DebugInstanceString => $"{GetType().ToString()} ({InstanceId})";
protected virtual void Dispose(bool disposing)
{
// do nothing here
}
protected void LogError(string message)
{
Logger.TraceEvent(TraceEventType.Error, 0, $"{DebugInstanceString} : " + message);
}
public void Dispose()
{
Stream.Dispose();
Dispose(false);
Logger.TraceInformation($"{DebugInstanceString} Service instance disposed");
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Execution;
using Roslyn.Utilities;
using StreamJsonRpc;
namespace Microsoft.CodeAnalysis.Remote
{
/// <summary>
/// Snapshot service in service hub side.
///
/// this service will be used to move over snapshot data from client to service hub
/// </summary>
internal class ServiceHubSnapshotService : ServiceHubJsonRpcServiceBase
{
private readonly AssetSource _source;
public ServiceHubSnapshotService(Stream stream, IServiceProvider serviceProvider) :
base(stream, serviceProvider)
{
_source = new ServiceHubAssetSource(Rpc, Logger, CancellationToken);
}
protected override void OnDisconnected(JsonRpcDisconnectedEventArgs e)
{
_source.Done();
}
private class ServiceHubAssetSource : AssetSource
{
private readonly JsonRpc _rpc;
private readonly TraceSource _logger;
private readonly CancellationToken _assetChannelCancellationToken;
public ServiceHubAssetSource(JsonRpc rpc, TraceSource logger, CancellationToken assetChannelCancellationToken) :
base()
{
_rpc = rpc;
_logger = logger;
_assetChannelCancellationToken = assetChannelCancellationToken;
}
public override async Task RequestAssetAsync(int serviceId, Checksum checksum, CancellationToken callerCancellationToken)
{
// it should succeed as long as matching VS is alive
// TODO: add logging mechanism using Logger
// this can be called in two ways.
// 1. Connection to get asset is closed (the asset source we were using is disconnected - _assetChannelCancellationToken)
// if this asset source's channel is closed, service will move to next asset source to get the asset as long as callerCancellationToken
// is not cancelled
//
// 2. Request to required this asset has cancelled. (callerCancellationToken)
using (var mergedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(_assetChannelCancellationToken, callerCancellationToken))
{
await _rpc.InvokeAsync(WellKnownServiceHubServices.AssetService_RequestAssetAsync,
new object[] { serviceId, checksum.ToArray() },
(s, c) => ReadAssetAsync(s, _logger, serviceId, checksum, c), mergedCancellationToken.Token).ConfigureAwait(false);
}
}
private static Task ReadAssetAsync(
Stream stream, TraceSource logger, int serviceId, Checksum checksum, CancellationToken cancellationToken)
{
using (var reader = new ObjectReader(stream))
{
var responseServiceId = reader.ReadInt32();
Contract.ThrowIfFalse(serviceId == responseServiceId);
var responseChecksum = new Checksum(reader.ReadArray<byte>());
Contract.ThrowIfFalse(checksum == responseChecksum);
var kind = reader.ReadString();
// in service hub, cancellation means simply closed stream
var @object = RoslynServices.AssetService.Deserialize<object>(kind, reader, cancellationToken);
RoslynServices.AssetService.Set(checksum, @object);
return SpecializedTasks.EmptyTask;
}
}
}
}
}
\ No newline at end of file
{
"dependencies": {
"StreamJsonRpc": "0.14.3-alpha"
},
"frameworks": {
"net46": {}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册