Skip to content

Commit

Permalink
Cache RootResource per endpoint rather than per repository
Browse files Browse the repository at this point in the history
  • Loading branch information
rosslovas committed Aug 15, 2024
1 parent d2af450 commit 11c457e
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusAsyncRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Task<IOctopusAsyncClient> AsUser(String, Octopus.Client.OctopusClientOptions)
Task<TResource> Create(String, Octopus.Client.TResource, Object)
Task<TResource> Create(String, Octopus.Client.TResource, CancellationToken)
Task<TResource> Create(String, Octopus.Client.TResource, Object, CancellationToken)
Expand Down Expand Up @@ -98,6 +99,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Octopus.Client.IOctopusClient AsUser(String, Octopus.Client.OctopusClientOptions)
Octopus.Client.TResource Create(String, Octopus.Client.TResource, Object)
Octopus.Client.TResponse Create(String, Octopus.Client.TCommand, Object)
void Delete(String, Object, Object)
Expand Down Expand Up @@ -169,6 +171,10 @@ Octopus.Client
Octopus.Client.IOctopusSystemRepository
{
}
interface IOctopusServerRootResourceCache
{
Octopus.Client.Model.RootResource CachedRootResource { get; set; }
}
interface IOctopusSpaceAsyncRepository
Octopus.Client.IOctopusCommonAsyncRepository
{
Expand Down Expand Up @@ -303,6 +309,7 @@ Octopus.Client
class OctopusAsyncClient
Octopus.Client.IOctopusAsyncClient
IDisposable
Octopus.Client.IOctopusServerRootResourceCache
{
event Action<HttpResponseMessage> AfterReceivedHttpResponse
event Action<HttpRequestMessage> BeforeSendingHttpRequest
Expand All @@ -311,6 +318,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusAsyncRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Task<IOctopusAsyncClient> AsUser(String, Octopus.Client.OctopusClientOptions)
static Task<IOctopusAsyncClient> Create(Octopus.Client.OctopusServerEndpoint, Octopus.Client.OctopusClientOptions)
Task<TResource> Create(String, Octopus.Client.TResource, Object)
Task<TResource> Create(String, Octopus.Client.TResource, CancellationToken)
Expand Down Expand Up @@ -451,6 +459,7 @@ Octopus.Client
Octopus.Client.IHttpOctopusClient
Octopus.Client.IOctopusClient
IDisposable
Octopus.Client.IOctopusServerRootResourceCache
{
event Action<WebResponse> AfterReceivingHttpResponse
event Action<WebRequest> BeforeSendingHttpRequest
Expand All @@ -460,6 +469,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Octopus.Client.IOctopusClient AsUser(String, Octopus.Client.OctopusClientOptions)
Octopus.Client.TResource Create(String, Octopus.Client.TResource, Object)
Octopus.Client.TResponse Create(String, Octopus.Client.TCommand, Object)
void Delete(String, Object, Object)
Expand Down Expand Up @@ -618,13 +628,15 @@ Octopus.Client
Octopus.Client.TResponseResource ResponseResource { get; }
}
class OctopusServerEndpoint
Octopus.Client.IOctopusServerRootResourceCache
{
.ctor(String)
.ctor(String, String)
.ctor(String, String, ICredentials)
.ctor(Octopus.Client.ILinkResolver, String, ICredentials)
String ApiKey { get; }
String BearerToken { get; }
Octopus.Client.Model.RootResource CachedRootResource { get; set; }
ICredentials Credentials { get; }
Boolean IsUsingSecureConnection { get; }
Octopus.Client.ILinkResolver OctopusServer { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusAsyncRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Task<IOctopusAsyncClient> AsUser(String, Octopus.Client.OctopusClientOptions)
Task<TResource> Create(String, Octopus.Client.TResource, Object)
Task<TResource> Create(String, Octopus.Client.TResource, CancellationToken)
Task<TResource> Create(String, Octopus.Client.TResource, Object, CancellationToken)
Expand Down Expand Up @@ -98,6 +99,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Octopus.Client.IOctopusClient AsUser(String, Octopus.Client.OctopusClientOptions)
Octopus.Client.TResource Create(String, Octopus.Client.TResource, Object)
Octopus.Client.TResponse Create(String, Octopus.Client.TCommand, Object)
void Delete(String, Object, Object)
Expand Down Expand Up @@ -169,6 +171,10 @@ Octopus.Client
Octopus.Client.IOctopusSystemRepository
{
}
interface IOctopusServerRootResourceCache
{
Octopus.Client.Model.RootResource CachedRootResource { get; set; }
}
interface IOctopusSpaceAsyncRepository
Octopus.Client.IOctopusCommonAsyncRepository
{
Expand Down Expand Up @@ -303,6 +309,7 @@ Octopus.Client
class OctopusAsyncClient
Octopus.Client.IOctopusAsyncClient
IDisposable
Octopus.Client.IOctopusServerRootResourceCache
{
event Action<HttpResponseMessage> AfterReceivedHttpResponse
event Action<HttpRequestMessage> BeforeSendingHttpRequest
Expand All @@ -311,6 +318,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusAsyncRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Task<IOctopusAsyncClient> AsUser(String, Octopus.Client.OctopusClientOptions)
static Task<IOctopusAsyncClient> Create(Octopus.Client.OctopusServerEndpoint, Octopus.Client.OctopusClientOptions)
Task<TResource> Create(String, Octopus.Client.TResource, Object)
Task<TResource> Create(String, Octopus.Client.TResource, CancellationToken)
Expand Down Expand Up @@ -451,6 +459,7 @@ Octopus.Client
Octopus.Client.IHttpOctopusClient
Octopus.Client.IOctopusClient
IDisposable
Octopus.Client.IOctopusServerRootResourceCache
{
event Action<WebResponse> AfterReceivingHttpResponse
event Action<WebRequest> BeforeSendingHttpRequest
Expand All @@ -460,6 +469,7 @@ Octopus.Client
Boolean IsUsingSecureConnection { get; }
Octopus.Client.IOctopusRepository Repository { get; }
Octopus.Client.Model.RootResource RootDocument { get; }
Octopus.Client.IOctopusClient AsUser(String, Octopus.Client.OctopusClientOptions)
Octopus.Client.TResource Create(String, Octopus.Client.TResource, Object)
Octopus.Client.TResponse Create(String, Octopus.Client.TCommand, Object)
void Delete(String, Object, Object)
Expand Down Expand Up @@ -616,13 +626,15 @@ Octopus.Client
Octopus.Client.TResponseResource ResponseResource { get; }
}
class OctopusServerEndpoint
Octopus.Client.IOctopusServerRootResourceCache
{
.ctor(String)
.ctor(String, String)
.ctor(String, String, ICredentials)
.ctor(Octopus.Client.ILinkResolver, String, ICredentials)
String ApiKey { get; }
String BearerToken { get; }
Octopus.Client.Model.RootResource CachedRootResource { get; set; }
ICredentials Credentials { get; }
Boolean IsUsingSecureConnection { get; }
Octopus.Client.ILinkResolver OctopusServer { get; }
Expand Down
2 changes: 2 additions & 0 deletions source/Octopus.Server.Client/IOctopusAsyncClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,8 @@ Task<TResponse> Create<TCommand, TResponse>(string path, TCommand command, objec
/// <returns></returns>
Task SignOut(CancellationToken cancellationToken);

Task<IOctopusAsyncClient> AsUser(string apiKey, OctopusClientOptions options = null);

/// <summary>
/// Get a repository for the given space
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions source/Octopus.Server.Client/IOctopusClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ public interface IOctopusClient : IDisposable
/// Sign out
/// </summary>
void SignOut();
IOctopusClient AsUser(string apiKey, OctopusClientOptions options = null);
IOctopusSpaceRepository ForSpace(SpaceResource space);
IOctopusSystemRepository ForSystem();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Octopus.Client.Model;

namespace Octopus.Client;

public interface IOctopusServerRootResourceCache
{
RootResource CachedRootResource { get; set; }
}
12 changes: 10 additions & 2 deletions source/Octopus.Server.Client/OctopusAsyncClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace Octopus.Client
/// <summary>
/// The Octopus Deploy RESTful HTTP API client.
/// </summary>
public class OctopusAsyncClient : IOctopusAsyncClient
public class OctopusAsyncClient : IOctopusAsyncClient, IOctopusServerRootResourceCache
{
private static readonly ILog Logger = LogProvider.For<OctopusAsyncClient>();

Expand Down Expand Up @@ -125,6 +125,8 @@ private bool IgnoreServerCertificateCallback(HttpRequestMessage message, X509Cer
return false;
}

public async Task<IOctopusAsyncClient> AsUser(string apiKey, OctopusClientOptions options = null) => await Create(serverEndpoint.AsUser(apiKey), options);

public IOctopusSpaceAsyncRepository ForSpace(SpaceResource space)
{
ValidateSpaceId(space);
Expand Down Expand Up @@ -271,7 +273,13 @@ public async Task SignOut(CancellationToken cancellationToken)
/// that it is only requested once for
/// the current <see cref="IOctopusAsyncClient" />.
/// </summary>
public RootResource RootDocument => Repository.LoadRootDocument().GetAwaiter().GetResult();
public RootResource RootDocument => (this as IOctopusServerRootResourceCache)?.CachedRootResource ?? Repository.LoadRootDocument().GetAwaiter().GetResult();

RootResource IOctopusServerRootResourceCache.CachedRootResource
{
get => serverEndpoint.CachedRootResource;
set => serverEndpoint.CachedRootResource = value;
}

/// <summary>
/// Occurs when a request is about to be sent.
Expand Down
12 changes: 11 additions & 1 deletion source/Octopus.Server.Client/OctopusAsyncRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ public async Task<string> Link(string name)

private async Task<RootResource> LoadRootDocumentInner(CancellationToken cancellationToken)
{
if (Client is IOctopusServerRootResourceCache { CachedRootResource: { } rootResource })
{
return rootResource;
}

var watch = Stopwatch.StartNew();
Exception lastError = null;

Expand Down Expand Up @@ -285,7 +290,12 @@ private async Task<RootResource> LoadRootDocumentInner(CancellationToken cancell

if (current < min || current > max)
throw new UnsupportedApiVersionException($"This Octopus Deploy server uses a newer API specification ({rootDocument.ApiVersion}) than this tool can handle ({ApiConstants.SupportedApiSchemaVersionMin} to {ApiConstants.SupportedApiSchemaVersionMax}). Please check for updates to this tool.");


if (Client is IOctopusServerRootResourceCache cache)
{
cache.CachedRootResource = rootDocument;
}

return rootDocument;
}

Expand Down
13 changes: 11 additions & 2 deletions source/Octopus.Server.Client/OctopusClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Octopus.Client
/// <summary>
/// The Octopus Deploy RESTful HTTP API client.
/// </summary>
public class OctopusClient : IHttpOctopusClient
public class OctopusClient : IHttpOctopusClient, IOctopusServerRootResourceCache
{
private static readonly ILog Logger = LogProvider.For<OctopusClient>();

Expand Down Expand Up @@ -53,14 +53,23 @@ internal OctopusClient(OctopusServerEndpoint serverEndpoint, string requestingTo
Repository = new OctopusRepository(this);
}

public RootResource RootDocument => Repository.LoadRootDocument();
public RootResource RootDocument => (this as IOctopusServerRootResourceCache)?.CachedRootResource ?? Repository.LoadRootDocument();

RootResource IOctopusServerRootResourceCache.CachedRootResource
{
get => serverEndpoint.CachedRootResource;
set => serverEndpoint.CachedRootResource = value;
}

public IOctopusRepository Repository { get; private set; }

/// <summary>
/// Indicates whether a secure (SSL) connection is being used to communicate with the server.
/// </summary>
public bool IsUsingSecureConnection => serverEndpoint.IsUsingSecureConnection;

public IOctopusClient AsUser(string apiKey, OctopusClientOptions options = null) => new OctopusClient(serverEndpoint.AsUser(apiKey), options);

public IOctopusSpaceRepository ForSpace(SpaceResource space)
{
ValidateSpaceId(space);
Expand Down
10 changes: 10 additions & 0 deletions source/Octopus.Server.Client/OctopusRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ public string Link(string name)

RootResource LoadRootDocumentInner()
{
if (Client is IOctopusServerRootResourceCache { CachedRootResource: { } rootResource })
{
return rootResource;
}

var watch = Stopwatch.StartNew();
Exception lastError = null;

Expand Down Expand Up @@ -270,6 +275,11 @@ RootResource LoadRootDocumentInner()
if (current < min || current > max)
throw new UnsupportedApiVersionException(string.Format("This Octopus Deploy server uses a newer API specification ({0}) than this tool can handle ({1} to {2}). Please check for updates to this tool.", rootDocument.ApiVersion, ApiConstants.SupportedApiSchemaVersionMin, ApiConstants.SupportedApiSchemaVersionMax));

if (Client is IOctopusServerRootResourceCache cache)
{
cache.CachedRootResource = rootDocument;
}

return rootDocument;
}

Expand Down
11 changes: 9 additions & 2 deletions source/Octopus.Server.Client/OctopusServerEndpoint.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System;
using System.Net;
using Octopus.Client.Model;

namespace Octopus.Client
{
/// <summary>
/// Specifies the location and credentials to use when communicating with an Octopus Deploy server.
/// </summary>
public class OctopusServerEndpoint
public class OctopusServerEndpoint : IOctopusServerRootResourceCache
{
/// <summary>
/// Create an instance with a Token to authenticate.
Expand Down Expand Up @@ -148,14 +149,20 @@ public OctopusServerEndpoint(ILinkResolver octopusServer, string apiKey, ICreden
/// <returns>An endpoint with a new user.</returns>
public OctopusServerEndpoint AsUser(string newUserApiKey)
{
return new OctopusServerEndpoint(OctopusServer, newUserApiKey, Credentials);
return new OctopusServerEndpoint(OctopusServer, newUserApiKey, Credentials)
{
// Preserve the cached root resource as we're still working with the same server, just a different API key
CachedRootResource = CachedRootResource,
};
}

/// <summary>
/// A proxy that should be used to connect to the endpoint.
/// </summary>
public IWebProxy Proxy { get; set; }

public RootResource CachedRootResource { get; set; } = null;

private static DefaultLinkResolver GetLinkResolverFromServerUrl(string octopusServerAddress)
{
if (string.IsNullOrWhiteSpace(octopusServerAddress))
Expand Down

0 comments on commit 11c457e

Please sign in to comment.