Commit API

main
ilitirit 3 years ago
parent 510fe2c2ba
commit d4b01c3eb2

@ -0,0 +1,101 @@
using System;
using Expedience.Api.Db;
using Expedience.Api.Db.Models;
using MassTransit;
namespace Expedience.Api.Consumers
{
public class DutyCompletionResultConsumer : IConsumer<Models.DutyCompletionResult>
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public DutyCompletionResultConsumer(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public async Task Consume(ConsumeContext<Models.DutyCompletionResult> context)
{
var message = context.Message;
using var scope = _serviceScopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<ExpedienceContext>();
if (message == null || message.UserInfo == null || message.PlayerInfo == null ||
message.DutyInfo == null || message.ClientInfo == null || message.CompletionTimeInfo == null)
{
// TODO: Log error
return;
}
var userHash = message.UserInfo.UserId;
var worldId = message.UserInfo.WorldId;
var user = dbContext.Users.FirstOrDefault(x => x.UserHash == userHash && x.WorldId == worldId);
if (user == null)
{
string userName;
do
{
userName = UserNameGenerator.Generate();
}
while (dbContext.Users.Any(x => x.UserName == userName && x.WorldId == worldId));
user = new User
{
UserHash = userHash,
WorldId = worldId,
UserName = userName,
CreatedAt = DateTime.UtcNow,
};
dbContext.Users.Add(user);
dbContext.SaveChanges();
}
var completionResult = new DutyCompletionResult
{
Id = message.UploadId,
DutyId = message.DutyInfo.DutyId,
UserId = user.UserId,
HasEcho = message.DutyInfo.HasEcho,
IsUnrestricted = message.DutyInfo.IsUnrestricted,
HasNpcMembers = message.DutyInfo.IsNpcSupported,
StartTime = message.DutyStartDateUtc,
EndTime = message.DutyCompletionDateUtc,
Hours = message.CompletionTimeInfo.Hours,
Minutes = message.CompletionTimeInfo.Minutes,
Seconds = message.CompletionTimeInfo.Seconds,
Milliseconds = message.CompletionTimeInfo.Milliseconds,
GameVersion = message.ClientInfo.GameVersion,
PluginVersion = message.ClientInfo.PluginVersion,
Language = message.ClientInfo.GameLanguage,
DataCenter = message.DataCenter,
};
dbContext.DutyCompletionResults.Add(completionResult);
var memberNumber = 0;
var dutyMembers = new List<DutyMember>();
foreach (var member in message.GroupMembers)
{
var dutyMember = new DutyMember
{
UploadId = message.UploadId,
GroupNumber = member.GroupNumber,
MemberNumber = memberNumber++,
ClassJob = member.ClassJob,
Level = member.Level,
IsNpc = member.IsNpc,
IsPlayer = member.IsPlayer,
};
dutyMembers.Add(dutyMember);
}
dbContext.DutyMembers.AddRange(dutyMembers);
await dbContext.SaveChangesAsync();
}
}
}

@ -0,0 +1,46 @@
using Expedience.Api.Encryption;
using Expedience.Models;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace Expedience.Api.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ExpedienceController : ControllerBase
{
private readonly ILogger<ExpedienceController> _logger;
private readonly IPublishEndpoint _publisher;
private readonly IDecryptor _decrypytor;
public ExpedienceController(ILogger<ExpedienceController> logger, IPublishEndpoint publisher, IDecryptor decrypytor)
{
_logger = logger;
_publisher = publisher;
_decrypytor = decrypytor;
}
[HttpPost("DutyCompletion")]
public async Task<ActionResult> PostDutyCompletionResult(List<string> encryptedPayloads)
{
var utcNow = DateTime.UtcNow;
try
{
foreach (var payload in encryptedPayloads)
{
var decryptedData = _decrypytor.Decrypt(payload);
var completionResult = JsonSerializer.Deserialize<DutyCompletionResult>(decryptedData)!;
completionResult.UploadDateUtc = utcNow;
await _publisher.Publish(completionResult);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error publishing completion result: {errorMessage}", ex.Message);
}
return Ok();
}
}
}

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
namespace Expedience.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

@ -0,0 +1,52 @@
using Expedience.Api.Db.Models;
using Microsoft.EntityFrameworkCore;
namespace Expedience.Api.Db
{
public class ExpedienceContext : DbContext
{
public ExpedienceContext(DbContextOptions<ExpedienceContext> dbContextOptions) : base(dbContextOptions)
{
}
public DbSet<DutyCompletionResult> DutyCompletionResults { get; set; }
public DbSet<DutyMember> DutyMembers { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DutyCompletionResult>(cfg =>
{
cfg.ToTable(nameof(DutyCompletionResult));
cfg.HasKey(e => e.Id);
});
modelBuilder.Entity<DutyMember>(cfg =>
{
cfg.ToTable(nameof(DutyMember));
cfg.HasKey(e => new { e.UploadId, e.GroupNumber, e.MemberNumber });
cfg.HasOne(o => o.DutyCompletionResult)
.WithMany(o => o.DutyMembers)
.HasForeignKey(o => o.UploadId);
});
modelBuilder.Entity<User>(cfg =>
{
cfg.ToTable(nameof(User));
cfg.Property(e => e.UserId)
.UseIdentityAlwaysColumn()
.IsRequired()
.ValueGeneratedOnAdd();
cfg.HasKey(e => new { e.UserId });
});
base.OnModelCreating(modelBuilder);
}
}
}

@ -0,0 +1,23 @@
namespace Expedience.Api.Db.Models
{
public class DutyCompletionResult
{
public Guid Id { get; set; }
public int UserId { get; set; }
public int DutyId { get; set; }
public bool HasEcho { get; set; }
public bool IsUnrestricted { get; set; }
public bool HasNpcMembers { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public int Hours { get; set; }
public int Minutes { get; set; }
public int Seconds { get; set; }
public int Milliseconds { get; set; }
public string GameVersion { get; set; }
public string PluginVersion { get; set; }
public string Language { get; set; }
public List<DutyMember> DutyMembers { get; set; }
public string DataCenter { get; set; }
}
}

@ -0,0 +1,14 @@
namespace Expedience.Api.Db.Models
{
public class DutyMember
{
public Guid UploadId { get; set; }
public int GroupNumber { get; set; }
public int MemberNumber { get; set; }
public string ClassJob { get; set; }
public int Level { get; set; }
public bool IsNpc { get; set; }
public bool IsPlayer { get; set; }
public DutyCompletionResult DutyCompletionResult { get; set; }
}
}

@ -0,0 +1,11 @@
namespace Expedience.Api.Db.Models
{
public class User
{
public int UserId { get; set; }
public int WorldId { get; set; }
public string UserHash { get; set; }
public string UserName { get; set; }
public DateTime CreatedAt { get; set; }
}
}

@ -0,0 +1,480 @@
using System;
namespace Expedience.Api.Db
{
public static class UserNameGenerator
{
private static readonly Random _random;
static UserNameGenerator()
{
int seed = (int)DateTime.Now.Ticks & 0x0000FFFF;
_random = new Random(seed);
}
public static string Generate()
{
var firstIndex = _random.Next(_adjectives.Count);
var lastIndex = _random.Next(_names.Count);
var firstName = _adjectives[firstIndex];
var lastName = _names[lastIndex];
return $"{firstName} {lastName}";
}
public static readonly List<string> _names = new List<string>()
{
"Strife",
"Valentine",
"Highwind",
"Gainsborough",
"Lockhart",
"Wallace",
"Leonhart",
"Zangan",
"Cidolfus",
"Kinneas",
"Trepe",
"Loire",
"Rinoa",
"Almasy",
"Caraway",
"Heartilly",
"Leonis",
"Harlow",
"Nox Fleuret",
"Ulric",
"Amicitia",
"Caelum",
"Scientia",
"Argentum",
"Aurum",
"Lucis",
"Estheim",
"Villiers",
"Farron",
"Katzroy",
"Nabaat",
"Yaag Rosch",
"Oerba",
"Paddra",
"Lesca",
"Folles",
"Zephyr",
"Martine",
"Beoulve",
"Gaffgarion",
"Loffrey",
"Mewt",
"Totema",
"Baert",
"Bervenia",
"Malak",
"Ladd",
"Kadaj",
"Loz",
"Yazoo",
"Jenova",
"Sephiroth",
"Hojo",
"Heidegger",
"Scarlet",
"Reeve",
"Palmer",
"Tseng",
"Reno",
"Rude",
"Elmyra",
"Fair",
"Gast",
"Nanaki",
"Shelke",
"Azul",
"Nero",
"Calca",
"Brina",
"Shirma",
"Hilda",
"Croma",
"Aleria",
"Reinhold",
"Rosenburg",
"Deneb",
"Cassiopeia",
"Vega",
"Altair",
"Antares",
"Andromeda",
"Cygnus",
"Fomalhaut",
"Aldebaran",
"Betelgeuse",
"Bellatrix",
"Regulus",
"Sirius",
"Arcturus",
"Pollux",
"Castor",
"Capella",
"Procyon",
"Achernar",
"Alphard",
"Alcyone",
"Atlas",
"Hyperion",
"Iapetus",
"Tethys",
"Cloud",
"Tifa",
"Aerith",
"Zack",
"Sephiroth",
"Vincent",
"Yuffie",
"Barret",
"Red XIII",
"Cait Sith",
"Cid",
"Squall",
"Rinoa",
"Selphie",
"Quistis",
"Zell",
"Irvine",
"Laguna",
"Kiros",
"Ward",
"Edea",
"Seifer",
"Ultimecia",
"Vivi",
"Garnet",
"Zidane",
"Steiner",
"Freya",
"Amarant",
"Beatrix",
"Eiko",
"Kuja",
"Tidus",
"Yuna",
"Wakka",
"Lulu",
"Kimahri",
"Auron",
"Rikku",
"Paine",
"Vaan",
"Ashe",
"Balthier",
"Fran",
"Basch",
"Lightning",
"Snow",
"Hope",
"Vanille",
"Fang",
"Serah",
"Noel",
"Caius",
"Rydia",
"Rosa",
"Cecil",
"Kain",
"Golbez",
"Edge",
"Porom",
"Palom",
"Terra",
"Locke",
"Celes",
"Edgar",
"Sabin",
"Shadow",
"Cyan",
"Setzer",
"Mog",
"Gau",
"Umaro",
"Relm",
"Strago",
"Gogo",
"Zemus",
"Fusoya",
"Tellah",
"Edward",
"Yang",
"Ursula",
"Firion",
"Maria",
"Guy",
"Leon",
"Minwu",
"Josef",
"Ricard",
"Refia",
"Luneth",
"Arc",
"Ingus",
"Krile",
"Galuf",
"Bartz",
"Lenna",
"Faris",
"Exdeath",
"Gilgamesh",
"Cidolfus"
};
public static List<string> _adjectives = new List<string>
{
"Adventurous",
"Affectionate",
"Agile",
"Ambitious",
"Amiable",
"Artistic",
"Assertive",
"Astute",
"Attentive",
"Authentic",
"Awesome",
"Balanced",
"Beautiful",
"Blissful",
"Bold",
"Brave",
"Bright",
"Brilliant",
"Calm",
"Capable",
"Carefree",
"Careful",
"Caring",
"Charismatic",
"Charming",
"Cheerful",
"Clean",
"Clear-minded",
"Clever",
"Colorful",
"Comfortable",
"Committed",
"Compassionate",
"Confident",
"Considerate",
"Consistent",
"Contemplative",
"Cooperative",
"Courageous",
"Courteous",
"Creative",
"Cultured",
"Curious",
"Daring",
"Dazzling",
"Decisive",
"Deep",
"Delightful",
"Dependable",
"Determined",
"Devoted",
"Diligent",
"Dynamic",
"Eager",
"Easygoing",
"Eccentric",
"Educated",
"Efficient",
"Elegant",
"Eloquent",
"Empathetic",
"Endearing",
"Energetic",
"Enthusiastic",
"Excellent",
"Exciting",
"Experienced",
"Expressive",
"Extraordinary",
"Exuberant",
"Fabulous",
"Fair",
"Faithful",
"Fantastic",
"Fearless",
"Fierce",
"Flamboyant",
"Flawless",
"Focused",
"Forgiving",
"Friendly",
"Fun",
"Funny",
"Generous",
"Gentle",
"Genuine",
"Gifted",
"Glorious",
"Graceful",
"Gracious",
"Grateful",
"Great",
"Hardworking",
"Harmonious",
"Healthy",
"Heartfelt",
"Helpful",
"Heroic",
"Honest",
"Honorable",
"Hopeful",
"Humble",
"Humorous",
"Idealistic",
"Imaginative",
"Impartial",
"Independent",
"Innovative",
"Inquisitive",
"Insightful",
"Inspiring",
"Intelligent",
"Intuitive",
"Inventive",
"Joyful",
"Jovial",
"Judicious",
"Just",
"Kind",
"Knowledgeable",
"Laid-back",
"Leisurely",
"Liberated",
"Lively",
"Logical",
"Lovable",
"Loving",
"Loyal",
"Lucid",
"Magical",
"Magnificent",
"Majestic",
"Masterful",
"Mature",
"Mellow",
"Meticulous",
"Mindful",
"Modest",
"Motivated",
"Mysterious",
"Nimble",
"Noble",
"Open-minded",
"Optimistic",
"Organized",
"Original",
"Outgoing",
"Passionate",
"Patient",
"Peaceful",
"Perfect",
"Persevering",
"Persistent",
"Playful",
"Pleasant",
"Polite",
"Positive",
"Powerful",
"Precise",
"Proactive",
"Progressive",
"Prosperous",
"Proud",
"Qualified",
"Quick",
"Quiet",
"Radiant",
"Rational",
"Realistic",
"Reflective",
"Relaxed",
"Reliable",
"Resilient",
"Resourceful",
"Respectful",
"Responsible",
"Robust",
"Romantic",
"Sane",
"Satisfying",
"Sensitive",
"Serene",
"Sharp",
"Shrewd",
"Sincere",
"Skillful",
"Smart",
"Smooth",
"Social",
"Solid",
"Sophisticated",
"Soulful",
"Sparkling",
"Special",
"Spiritual",
"Spontaneous",
"Stable",
"Steadfast",
"Steady",
"Strong",
"Stunning",
"Successful",
"Superb",
"Supportive",
"Surprising",
"Sweet",
"Sympathetic",
"Systematic",
"Tactful",
"Talented",
"Tenacious",
"Thankful",
"Thorough",
"Thoughtful",
"Thrilled",
"Thriving",
"Tidy",
"Timely",
"Tolerant",
"Tranquil",
"Transparent",
"Trustworthy",
"Unassuming",
"Understanding",
"Unique",
"Unselfish",
"Unwavering",
"Upbeat",
"Valiant",
"Versatile",
"Vibrant",
"Victorious",
"Vigilant",
"Vigorous",
"Virtuous",
"Visionary",
"Vital",
"Vivacious",
"Warm",
"Welcoming",
"Wholehearted",
"Willing",
"Wise",
"Witty",
"Wonderful",
"Worthy",
"Youthful",
"Zealous",
"Zest"
};
}
}

@ -0,0 +1,39 @@
# Set the base image
FROM mcr.microsoft.com/dotnet/sdk:7.0.202-jammy-arm64v8 AS build
# Set the working directory
WORKDIR /src
# Copy the project files
COPY Expedience.Models/Expedience.Models.csproj Expedience.Models/
COPY Expedience.Api/Expedience.Api.csproj Expedience.Api/
# Restore the packages
RUN dotnet restore Expedience.Api/Expedience.Api.csproj
COPY . .
# Build the project
RUN dotnet build "Expedience.Api/Expedience.Api.csproj" -c Release -o /app/build
# Publish the project
ARG TARGET_RUNTIME=linux-x64
RUN dotnet publish "Expedience.Api/Expedience.Api.csproj" -c Release -o /app/publish --self-contained --runtime $TARGET_RUNTIME
# Set the base image for the final runtime
FROM mcr.microsoft.com/dotnet/aspnet:7.0.4-jammy-arm64v8
# Set the working directory
WORKDIR /app
# Copy the published files
COPY --from=build /app/publish .
# Set the ASPNETCORE_ENVIRONMENT environment variable
ENV ASPNETCORE_ENVIRONMENT=Production
# Expose the port the application will run on
EXPOSE 7033
# Set the entry point for the container
ENTRYPOINT ["dotnet", "Expedience.Api.dll"]

@ -0,0 +1,51 @@
using RabbitMQ.Client;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Text;
namespace Expedience.Api.Encryption
{
public interface IDecryptor
{
string Decrypt(string data);
}
public class Decryptor : IDecryptor
{
private RSACryptoServiceProvider _csp;
public Decryptor()
{
_csp = new RSACryptoServiceProvider();
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Expedience.Api.key.bin")
?? throw new NullReferenceException("Could not get key.bin resource");
using var memorySteam = new MemoryStream();
stream.CopyTo(memorySteam);
var bytes = memorySteam.ToArray();
_csp.ImportCspBlob(bytes);
}
public string Decrypt(string data)
{
var encryptedData = Convert.FromBase64String(data);
// Split the encrypted data into chunks
byte[] decryptedData = Array.Empty<byte>();
for (int i = 0; i < encryptedData.Length; i += _csp.KeySize / 8)
{
int dataSize = _csp.KeySize / 8;
byte[] chunk = new byte[dataSize];
Array.Copy(encryptedData, i, chunk, 0, dataSize);
// Decrypt the chunk of data
byte[] decryptedChunk = _csp.Decrypt(chunk, false);
decryptedData = decryptedData.Concat(decryptedChunk).ToArray();
}
return Encoding.UTF8.GetString(decryptedData);
}
}
}

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\Expedience</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<None Remove="key.bin" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="key.bin" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.14" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Expedience.Models\Expedience.Models.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Db\Repositories\" />
</ItemGroup>
</Project>

@ -0,0 +1,54 @@
using Expedience.Api.Consumers;
using Expedience.Api.Db;
using Expedience.Api.Encryption;
using MassTransit;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("Expedience");
builder.Services.AddDbContext<ExpedienceContext>(options =>
options.UseNpgsql(connectionString));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var rabbitMqHost = builder.Configuration.GetSection("RabbitMq")["Host"];
builder.Services.AddMassTransit(opt =>
{
opt.AddConsumersFromNamespaceContaining<DutyCompletionResultConsumer>();
opt.UsingRabbitMq((context, cfg) =>
{
cfg.Host(rabbitMqHost);
cfg.ConfigureEndpoints(context);
});
});
builder.Services.AddSingleton<IDecryptor, Decryptor>();
var app = builder.Build();
var scope = app.Services.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<ExpedienceContext>();
dbContext.Database.EnsureCreated();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

@ -0,0 +1,41 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:16060",
"sslPort": 44320
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5168",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7033;http://localhost:5168",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

@ -0,0 +1,13 @@
namespace Expedience.Api
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: expedience-api-deployment
namespace: expedience
spec:
replicas: 1
selector:
matchLabels:
app: expedience-api
template:
metadata:
labels:
app: expedience-api
spec:
containers:
- name: expedience-api
image: registry.ilitirit.net/expedience-api:latest
ports:
- containerPort: 7033
imagePullSecrets:
- name: registry-credentials

@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: expedience-api-ingress
namespace: expedience
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- expedience-api.ilitirit.net
secretName: expedience-api-certificate
rules:
- host: expedience-api.ilitirit.net
http:
paths:
- pathType: ImplementationSpecific
backend:
service:
name: expedience-api-service
port:
number: 7033

@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: expedience-api-service
namespace: expedience
spec:
selector:
app: expedience-api
ports:
- protocol: TCP
port: 7033
targetPort: 7033
type: ClusterIP
Loading…
Cancel
Save