mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-09-18 10:42:42 +08:00
removed rafty and updated more packages
This commit is contained in:
@@ -28,8 +28,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="KubeClient" Version="2.3.11" />
|
||||
<PackageReference Include="KubeClient.Extensions.DependencyInjection" Version="2.3.11" />
|
||||
<PackageReference Include="KubeClient" Version="2.3.15" />
|
||||
<PackageReference Include="KubeClient.Extensions.DependencyInjection" Version="2.3.15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -1,16 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
|
||||
internal class BearerToken
|
||||
{
|
||||
[JsonProperty("access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
[JsonProperty("expires_in")]
|
||||
public int ExpiresIn { get; set; }
|
||||
|
||||
[JsonProperty("token_type")]
|
||||
public string TokenType { get; set; }
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using global::Rafty.FiniteStateMachine;
|
||||
|
||||
public class FakeCommand : ICommand
|
||||
{
|
||||
public FakeCommand(string value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public string Value { get; private set; }
|
||||
}
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
public class FilePeer
|
||||
{
|
||||
public string HostAndPort { get; set; }
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class FilePeers
|
||||
{
|
||||
public FilePeers()
|
||||
{
|
||||
Peers = new List<FilePeer>();
|
||||
}
|
||||
|
||||
public List<FilePeer> Peers { get; set; }
|
||||
}
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Administration;
|
||||
using Configuration.Repository;
|
||||
using global::Rafty.Concensus.Peers;
|
||||
using global::Rafty.Infrastructure;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Middleware;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
|
||||
public class FilePeersProvider : IPeersProvider
|
||||
{
|
||||
private readonly IOptions<FilePeers> _options;
|
||||
private readonly List<IPeer> _peers;
|
||||
private IBaseUrlFinder _finder;
|
||||
private IInternalConfigurationRepository _repo;
|
||||
private IIdentityServerConfiguration _identityServerConfig;
|
||||
|
||||
public FilePeersProvider(IOptions<FilePeers> options, IBaseUrlFinder finder, IInternalConfigurationRepository repo, IIdentityServerConfiguration identityServerConfig)
|
||||
{
|
||||
_identityServerConfig = identityServerConfig;
|
||||
_repo = repo;
|
||||
_finder = finder;
|
||||
_options = options;
|
||||
_peers = new List<IPeer>();
|
||||
|
||||
var config = _repo.Get();
|
||||
foreach (var item in _options.Value.Peers)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
|
||||
//todo what if this errors?
|
||||
var httpPeer = new HttpPeer(item.HostAndPort, httpClient, _finder, config.Data, _identityServerConfig);
|
||||
_peers.Add(httpPeer);
|
||||
}
|
||||
}
|
||||
|
||||
public List<IPeer> Get()
|
||||
{
|
||||
return _peers;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,130 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Administration;
|
||||
using Configuration;
|
||||
using global::Rafty.Concensus.Messages;
|
||||
using global::Rafty.Concensus.Peers;
|
||||
using global::Rafty.FiniteStateMachine;
|
||||
using global::Rafty.Infrastructure;
|
||||
using Middleware;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class HttpPeer : IPeer
|
||||
{
|
||||
private readonly string _hostAndPort;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly JsonSerializerSettings _jsonSerializerSettings;
|
||||
private readonly string _baseSchemeUrlAndPort;
|
||||
private BearerToken _token;
|
||||
private readonly IInternalConfiguration _config;
|
||||
private readonly IIdentityServerConfiguration _identityServerConfiguration;
|
||||
|
||||
public HttpPeer(string hostAndPort, HttpClient httpClient, IBaseUrlFinder finder, IInternalConfiguration config, IIdentityServerConfiguration identityServerConfiguration)
|
||||
{
|
||||
_identityServerConfiguration = identityServerConfiguration;
|
||||
_config = config;
|
||||
Id = hostAndPort;
|
||||
_hostAndPort = hostAndPort;
|
||||
_httpClient = httpClient;
|
||||
_jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
_baseSchemeUrlAndPort = finder.Find();
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
|
||||
public async Task<RequestVoteResponse> Request(RequestVote requestVote)
|
||||
{
|
||||
if (_token == null)
|
||||
{
|
||||
await SetToken();
|
||||
}
|
||||
|
||||
var json = JsonConvert.SerializeObject(requestVote, _jsonSerializerSettings);
|
||||
var content = new StringContent(json);
|
||||
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
|
||||
var response = await _httpClient.PostAsync($"{_hostAndPort}/administration/raft/requestvote", content);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<RequestVoteResponse>(await response.Content.ReadAsStringAsync(), _jsonSerializerSettings);
|
||||
}
|
||||
|
||||
return new RequestVoteResponse(false, requestVote.Term);
|
||||
}
|
||||
|
||||
public async Task<AppendEntriesResponse> Request(AppendEntries appendEntries)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_token == null)
|
||||
{
|
||||
await SetToken();
|
||||
}
|
||||
|
||||
var json = JsonConvert.SerializeObject(appendEntries, _jsonSerializerSettings);
|
||||
var content = new StringContent(json);
|
||||
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
|
||||
var response = await _httpClient.PostAsync($"{_hostAndPort}/administration/raft/appendEntries", content);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<AppendEntriesResponse>(await response.Content.ReadAsStringAsync(), _jsonSerializerSettings);
|
||||
}
|
||||
|
||||
return new AppendEntriesResponse(appendEntries.Term, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
return new AppendEntriesResponse(appendEntries.Term, false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Response<T>> Request<T>(T command)
|
||||
where T : ICommand
|
||||
{
|
||||
Console.WriteLine("SENDING REQUEST....");
|
||||
if (_token == null)
|
||||
{
|
||||
await SetToken();
|
||||
}
|
||||
|
||||
var json = JsonConvert.SerializeObject(command, _jsonSerializerSettings);
|
||||
var content = new StringContent(json);
|
||||
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
|
||||
var response = await _httpClient.PostAsync($"{_hostAndPort}/administration/raft/command", content);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine("REQUEST OK....");
|
||||
var okResponse = JsonConvert.DeserializeObject<OkResponse<ICommand>>(await response.Content.ReadAsStringAsync(), _jsonSerializerSettings);
|
||||
return new OkResponse<T>((T)okResponse.Command);
|
||||
}
|
||||
|
||||
Console.WriteLine("REQUEST NOT OK....");
|
||||
return new ErrorResponse<T>(await response.Content.ReadAsStringAsync(), command);
|
||||
}
|
||||
|
||||
private async Task SetToken()
|
||||
{
|
||||
var tokenUrl = $"{_baseSchemeUrlAndPort}{_config.AdministrationPath}/connect/token";
|
||||
var formData = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("client_id", _identityServerConfiguration.ApiName),
|
||||
new KeyValuePair<string, string>("client_secret", _identityServerConfiguration.ApiSecret),
|
||||
new KeyValuePair<string, string>("scope", _identityServerConfiguration.ApiName),
|
||||
new KeyValuePair<string, string>("grant_type", "client_credentials")
|
||||
};
|
||||
var content = new FormUrlEncodedContent(formData);
|
||||
var response = await _httpClient.PostAsync(tokenUrl, content);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
response.EnsureSuccessStatusCode();
|
||||
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
|
||||
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(_token.TokenType, _token.AccessToken);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Provides Ocelot extensions to use Rafty</Description>
|
||||
<AssemblyTitle>Ocelot.Provider.Rafty</AssemblyTitle>
|
||||
<VersionPrefix>0.0.0-dev</VersionPrefix>
|
||||
<AssemblyName>Ocelot.Provider.Rafty</AssemblyName>
|
||||
<PackageId>Ocelot.Provider.Rafty</PackageId>
|
||||
<PackageTags>API Gateway;.NET core</PackageTags>
|
||||
<PackageProjectUrl>https://github.com/ThreeMammals/Ocelot.Provider.Rafty</PackageProjectUrl>
|
||||
<PackageProjectUrl>https://github.com/ThreeMammals/Ocelot.Provider.Rafty</PackageProjectUrl>
|
||||
<PackageIconUrl>http://threemammals.com/images/ocelot_logo.png</PackageIconUrl>
|
||||
<RuntimeIdentifiers>win10-x64;osx.10.11-x64;osx.10.12-x64;win7-x64</RuntimeIdentifiers>
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
||||
<Authors>Tom Pallister</Authors>
|
||||
<CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||
<ProjectReference Include="..\Ocelot.Administration\Ocelot.Administration.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="3.1.1" />
|
||||
<PackageReference Include="Rafty" Version="0.4.4" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.164">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -1,28 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Configuration.Setter;
|
||||
using DependencyInjection;
|
||||
using global::Rafty.Concensus.Node;
|
||||
using global::Rafty.FiniteStateMachine;
|
||||
using global::Rafty.Infrastructure;
|
||||
using global::Rafty.Log;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
public static class OcelotAdministrationBuilderExtensions
|
||||
{
|
||||
public static IOcelotAdministrationBuilder AddRafty(this IOcelotAdministrationBuilder builder)
|
||||
{
|
||||
var settings = new InMemorySettings(4000, 6000, 100, 10000);
|
||||
builder.Services.RemoveAll<IFileConfigurationSetter>();
|
||||
builder.Services.AddSingleton<IFileConfigurationSetter, RaftyFileConfigurationSetter>();
|
||||
builder.Services.AddSingleton<ILog, SqlLiteLog>();
|
||||
builder.Services.AddSingleton<IFiniteStateMachine, OcelotFiniteStateMachine>();
|
||||
builder.Services.AddSingleton<ISettings>(settings);
|
||||
builder.Services.AddSingleton<IPeersProvider, FilePeersProvider>();
|
||||
builder.Services.AddSingleton<INode, Node>();
|
||||
builder.Services.Configure<FilePeers>(builder.ConfigurationRoot);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Configuration.Setter;
|
||||
using global::Rafty.FiniteStateMachine;
|
||||
using global::Rafty.Log;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class OcelotFiniteStateMachine : IFiniteStateMachine
|
||||
{
|
||||
private readonly IFileConfigurationSetter _setter;
|
||||
|
||||
public OcelotFiniteStateMachine(IFileConfigurationSetter setter)
|
||||
{
|
||||
_setter = setter;
|
||||
}
|
||||
|
||||
public async Task Handle(LogEntry log)
|
||||
{
|
||||
//todo - handle an error
|
||||
//hack it to just cast as at the moment we know this is the only command :P
|
||||
var hack = (UpdateFileConfiguration)log.CommandData;
|
||||
await _setter.Set(hack.Configuration);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Ocelot")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("d6df4206-0dba-41d8-884d-c3e08290fdbb")]
|
@@ -1,96 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using global::Rafty.Concensus.Messages;
|
||||
using global::Rafty.Concensus.Node;
|
||||
using global::Rafty.FiniteStateMachine;
|
||||
using Logging;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Middleware;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[Authorize]
|
||||
[Route("raft")]
|
||||
public class RaftController : Controller
|
||||
{
|
||||
private readonly INode _node;
|
||||
private readonly IOcelotLogger _logger;
|
||||
private readonly string _baseSchemeUrlAndPort;
|
||||
private readonly JsonSerializerSettings _jsonSerialiserSettings;
|
||||
|
||||
public RaftController(INode node, IOcelotLoggerFactory loggerFactory, IBaseUrlFinder finder)
|
||||
{
|
||||
_jsonSerialiserSettings = new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
_baseSchemeUrlAndPort = finder.Find();
|
||||
_logger = loggerFactory.CreateLogger<RaftController>();
|
||||
_node = node;
|
||||
}
|
||||
|
||||
[Route("appendentries")]
|
||||
public async Task<IActionResult> AppendEntries()
|
||||
{
|
||||
using (var reader = new StreamReader(HttpContext.Request.Body))
|
||||
{
|
||||
var json = await reader.ReadToEndAsync();
|
||||
|
||||
var appendEntries = JsonConvert.DeserializeObject<AppendEntries>(json, _jsonSerialiserSettings);
|
||||
|
||||
_logger.LogDebug($"{_baseSchemeUrlAndPort}/appendentries called, my state is {_node.State.GetType().FullName}");
|
||||
|
||||
var appendEntriesResponse = await _node.Handle(appendEntries);
|
||||
|
||||
return new OkObjectResult(appendEntriesResponse);
|
||||
}
|
||||
}
|
||||
|
||||
[Route("requestvote")]
|
||||
public async Task<IActionResult> RequestVote()
|
||||
{
|
||||
using (var reader = new StreamReader(HttpContext.Request.Body))
|
||||
{
|
||||
var json = await reader.ReadToEndAsync();
|
||||
|
||||
var requestVote = JsonConvert.DeserializeObject<RequestVote>(json, _jsonSerialiserSettings);
|
||||
|
||||
_logger.LogDebug($"{_baseSchemeUrlAndPort}/requestvote called, my state is {_node.State.GetType().FullName}");
|
||||
|
||||
var requestVoteResponse = await _node.Handle(requestVote);
|
||||
|
||||
return new OkObjectResult(requestVoteResponse);
|
||||
}
|
||||
}
|
||||
|
||||
[Route("command")]
|
||||
public async Task<IActionResult> Command()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var reader = new StreamReader(HttpContext.Request.Body))
|
||||
{
|
||||
var json = await reader.ReadToEndAsync();
|
||||
|
||||
var command = JsonConvert.DeserializeObject<ICommand>(json, _jsonSerialiserSettings);
|
||||
|
||||
_logger.LogDebug($"{_baseSchemeUrlAndPort}/command called, my state is {_node.State.GetType().FullName}");
|
||||
|
||||
var commandResponse = await _node.Accept(command);
|
||||
|
||||
json = JsonConvert.SerializeObject(commandResponse, _jsonSerialiserSettings);
|
||||
|
||||
return StatusCode(200, json);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError($"THERE WAS A PROBLEM ON NODE {_node.State.CurrentState.Id}", e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Configuration.File;
|
||||
using Configuration.Setter;
|
||||
using global::Rafty.Concensus.Node;
|
||||
using global::Rafty.Infrastructure;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class RaftyFileConfigurationSetter : IFileConfigurationSetter
|
||||
{
|
||||
private readonly INode _node;
|
||||
|
||||
public RaftyFileConfigurationSetter(INode node)
|
||||
{
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public async Task<Responses.Response> Set(FileConfiguration fileConfiguration)
|
||||
{
|
||||
var result = await _node.Accept(new UpdateFileConfiguration(fileConfiguration));
|
||||
|
||||
if (result.GetType() == typeof(ErrorResponse<UpdateFileConfiguration>))
|
||||
{
|
||||
return new Responses.ErrorResponse(new UnableToSaveAcceptCommand($"unable to save file configuration to state machine"));
|
||||
}
|
||||
|
||||
return new Responses.OkResponse();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using global::Rafty.Concensus.Node;
|
||||
using global::Rafty.Infrastructure;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Middleware;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class RaftyMiddlewareConfigurationProvider
|
||||
{
|
||||
public static OcelotMiddlewareConfigurationDelegate Get = builder =>
|
||||
{
|
||||
if (UsingRafty(builder))
|
||||
{
|
||||
SetUpRafty(builder);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
private static bool UsingRafty(IApplicationBuilder builder)
|
||||
{
|
||||
var node = builder.ApplicationServices.GetService<INode>();
|
||||
if (node != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void SetUpRafty(IApplicationBuilder builder)
|
||||
{
|
||||
var applicationLifetime = builder.ApplicationServices.GetService<IApplicationLifetime>();
|
||||
applicationLifetime.ApplicationStopping.Register(() => OnShutdown(builder));
|
||||
var node = builder.ApplicationServices.GetService<INode>();
|
||||
var nodeId = builder.ApplicationServices.GetService<NodeId>();
|
||||
node.Start(nodeId);
|
||||
}
|
||||
|
||||
private static void OnShutdown(IApplicationBuilder app)
|
||||
{
|
||||
var node = app.ApplicationServices.GetService<INode>();
|
||||
node.Stop();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,334 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using global::Rafty.Infrastructure;
|
||||
using global::Rafty.Log;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class SqlLiteLog : ILog
|
||||
{
|
||||
private readonly string _path;
|
||||
private readonly SemaphoreSlim _sempaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly ILogger _logger;
|
||||
private readonly NodeId _nodeId;
|
||||
|
||||
public SqlLiteLog(NodeId nodeId, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<SqlLiteLog>();
|
||||
_nodeId = nodeId;
|
||||
_path = $"{nodeId.Id.Replace("/", "").Replace(":", "")}.db";
|
||||
_sempaphore.Wait();
|
||||
|
||||
if (!File.Exists(_path))
|
||||
{
|
||||
var fs = File.Create(_path);
|
||||
|
||||
fs.Dispose();
|
||||
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
const string sql = @"create table logs (
|
||||
id integer primary key,
|
||||
data text not null
|
||||
)";
|
||||
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var result = command.ExecuteNonQuery();
|
||||
|
||||
_logger.LogInformation(result == 0
|
||||
? $"id: {_nodeId.Id} create database, result: {result}"
|
||||
: $"id: {_nodeId.Id} did not create database., result: {result}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
}
|
||||
|
||||
public async Task<int> LastLogIndex()
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
var result = 1;
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
var sql = @"select id from logs order by id desc limit 1";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var index = Convert.ToInt32(await command.ExecuteScalarAsync());
|
||||
if (index > result)
|
||||
{
|
||||
result = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<long> LastLogTerm()
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
long result = 0;
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
var sql = @"select data from logs order by id desc limit 1";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var data = Convert.ToString(await command.ExecuteScalarAsync());
|
||||
var jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
var log = JsonConvert.DeserializeObject<LogEntry>(data, jsonSerializerSettings);
|
||||
if (log != null && log.Term > result)
|
||||
{
|
||||
result = log.Term;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> Count()
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
var result = 0;
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
var sql = @"select count(id) from logs";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var index = Convert.ToInt32(await command.ExecuteScalarAsync());
|
||||
if (index > result)
|
||||
{
|
||||
result = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> Apply(LogEntry log)
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
var jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
var data = JsonConvert.SerializeObject(log, jsonSerializerSettings);
|
||||
|
||||
//todo - sql injection dont copy this..
|
||||
var sql = $"insert into logs (data) values ('{data}')";
|
||||
_logger.LogInformation($"id: {_nodeId.Id}, sql: {sql}");
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var result = await command.ExecuteNonQueryAsync();
|
||||
_logger.LogInformation($"id: {_nodeId.Id}, insert log result: {result}");
|
||||
}
|
||||
|
||||
sql = "select last_insert_rowid()";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var result = await command.ExecuteScalarAsync();
|
||||
_logger.LogInformation($"id: {_nodeId.Id}, about to release semaphore");
|
||||
_sempaphore.Release();
|
||||
_logger.LogInformation($"id: {_nodeId.Id}, saved log to sqlite");
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteConflictsFromThisLog(int index, LogEntry logEntry)
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
//todo - sql injection dont copy this..
|
||||
var sql = $"select data from logs where id = {index};";
|
||||
_logger.LogInformation($"id: {_nodeId.Id} sql: {sql}");
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var data = Convert.ToString(await command.ExecuteScalarAsync());
|
||||
var jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
|
||||
_logger.LogInformation($"id {_nodeId.Id} got log for index: {index}, data is {data} and new log term is {logEntry.Term}");
|
||||
|
||||
var log = JsonConvert.DeserializeObject<LogEntry>(data, jsonSerializerSettings);
|
||||
if (logEntry != null && log != null && logEntry.Term != log.Term)
|
||||
{
|
||||
//todo - sql injection dont copy this..
|
||||
var deleteSql = $"delete from logs where id >= {index};";
|
||||
_logger.LogInformation($"id: {_nodeId.Id} sql: {deleteSql}");
|
||||
using (var deleteCommand = new SqliteCommand(deleteSql, connection))
|
||||
{
|
||||
var result = await deleteCommand.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
}
|
||||
|
||||
public async Task<bool> IsDuplicate(int index, LogEntry logEntry)
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
//todo - sql injection dont copy this..
|
||||
var sql = $"select data from logs where id = {index};";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var data = Convert.ToString(await command.ExecuteScalarAsync());
|
||||
var jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
|
||||
var log = JsonConvert.DeserializeObject<LogEntry>(data, jsonSerializerSettings);
|
||||
|
||||
if (logEntry != null && log != null && logEntry.Term == log.Term)
|
||||
{
|
||||
_sempaphore.Release();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<LogEntry> Get(int index)
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
//todo - sql injection dont copy this..
|
||||
var sql = $"select data from logs where id = {index}";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var data = Convert.ToString(await command.ExecuteScalarAsync());
|
||||
var jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
var log = JsonConvert.DeserializeObject<LogEntry>(data, jsonSerializerSettings);
|
||||
_sempaphore.Release();
|
||||
return log;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<(int index, LogEntry logEntry)>> GetFrom(int index)
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
var logsToReturn = new List<(int, LogEntry)>();
|
||||
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
//todo - sql injection dont copy this..
|
||||
var sql = $"select id, data from logs where id >= {index}";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
using (var reader = await command.ExecuteReaderAsync())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var id = Convert.ToInt32(reader[0]);
|
||||
var data = (string)reader[1];
|
||||
var jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
var log = JsonConvert.DeserializeObject<LogEntry>(data, jsonSerializerSettings);
|
||||
logsToReturn.Add((id, log));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
return logsToReturn;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<long> GetTermAtIndex(int index)
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
long result = 0;
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
//todo - sql injection dont copy this..
|
||||
var sql = $"select data from logs where id = {index}";
|
||||
using (var command = new SqliteCommand(sql, connection))
|
||||
{
|
||||
var data = Convert.ToString(await command.ExecuteScalarAsync());
|
||||
var jsonSerializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
var log = JsonConvert.DeserializeObject<LogEntry>(data, jsonSerializerSettings);
|
||||
if (log != null && log.Term > result)
|
||||
{
|
||||
result = log.Term;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task Remove(int indexOfCommand)
|
||||
{
|
||||
_sempaphore.Wait();
|
||||
using (var connection = new SqliteConnection($"Data Source={_path};"))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
//todo - sql injection dont copy this..
|
||||
var deleteSql = $"delete from logs where id >= {indexOfCommand};";
|
||||
_logger.LogInformation($"id: {_nodeId.Id} Remove {deleteSql}");
|
||||
using (var deleteCommand = new SqliteCommand(deleteSql, connection))
|
||||
{
|
||||
var result = await deleteCommand.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
|
||||
_sempaphore.Release();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Errors;
|
||||
|
||||
public class UnableToSaveAcceptCommand : Error
|
||||
{
|
||||
public UnableToSaveAcceptCommand(string message)
|
||||
: base(message, OcelotErrorCode.UnknownError, 404)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
namespace Ocelot.Provider.Rafty
|
||||
{
|
||||
using Configuration.File;
|
||||
using global::Rafty.FiniteStateMachine;
|
||||
|
||||
public class UpdateFileConfiguration : ICommand
|
||||
{
|
||||
public UpdateFileConfiguration(FileConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public FileConfiguration Configuration { get; private set; }
|
||||
}
|
||||
}
|
@@ -25,11 +25,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentValidation" Version="9.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.MiddlewareAnalysis" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="3.1.3">
|
||||
<PackageReference Include="Microsoft.AspNetCore.MiddlewareAnalysis" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="3.1.10">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.164">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
Reference in New Issue
Block a user