1
0

complete lab2 rest

This commit is contained in:
Rokas Puzonas 2024-10-17 20:31:08 +03:00
parent 5bf5699a51
commit 4d2e40282d
17 changed files with 2061 additions and 0 deletions

38
Lab2-rest/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,38 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "ChatRoom",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-ChatRoom",
"program": "${workspaceFolder}/ChatRoom/bin/Debug/net6.0/ChatRoom.dll",
"args": [],
"cwd": "${workspaceFolder}/ChatRoom",
"console": "externalTerminal",
"stopAtEntry": false
},
{
"name": "Moderator",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-Moderator",
"program": "${workspaceFolder}/Moderator/bin/Debug/net6.0/Moderator.dll",
"args": [],
"cwd": "${workspaceFolder}/Moderator",
"console": "externalTerminal",
"stopAtEntry": false
},
{
"name": "Participant",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-Participant",
"program": "${workspaceFolder}/Participant/bin/Debug/net6.0/Participant.dll",
"args": [],
"cwd": "${workspaceFolder}/Participant",
"console": "externalTerminal",
"stopAtEntry": false
}
]
}

41
Lab2-rest/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build-ChatRoom",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/ChatRoom/ChatRoom.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build-Moderator",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Moderator/Moderator.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build-Participant",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Participant/Participant.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ChatRoomContract\ChatRoomContract.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,295 @@
using NLog;
namespace ChatRoom;
/// <summary>
/// Chat room service logic
/// </summary>
public class ChatRoomLogic
{
/// <summary>
/// Background thread of deleting approved or rejected messages
/// </summary>
private Thread thread;
/// <summary>
/// Chat Room state
/// </summary>
private ChatRoomState state = new ChatRoomState();
/// <summary>
/// Logger
/// </summary>
private Logger log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Chat room logic constructor
/// </summary>
public ChatRoomLogic()
{
thread = new Thread(BackgroundTask);
thread.Start();
}
/// <summary>
/// Generate the next incrementing ID
/// </summary>
/// <returns>Unique ID</returns>
int NextId()
{
int id = state.lastUniqueId;
state.lastUniqueId++;
return id;
}
/// <summary>
/// Register a client
/// </summary>
/// <param name="name">Client name</param>
/// <returns>Client ID</returns>
public int RegisterClient(string name)
{
lock (state.accessLock)
{
int clientId = NextId();
state.clients.Add(new Client
{
id = clientId,
name = name
});
log.Info($"Registered with client '{name}' with id {clientId}");
return clientId;
}
}
/// <summary>
/// Find a client by ID, can return NULL if not found
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Optional client object</returns>
Client? FindClientById(int clientId)
{
foreach (var client in state.clients)
{
if (client.id == clientId)
{
return client;
}
}
return null;
}
/// <summary>
/// Find message by ID, can return NULL if not found
/// </summary>
/// <param name="messageId">Message ID</param>
/// <returns>Optional message object</returns>
Message? FindMessageById(int messageId)
{
foreach (var message in state.messages)
{
if (message.id == messageId)
{
return message;
}
}
return null;
}
/// <summary>
/// Check if client is still blocked, will clear `blockedUntil` if client became unblocked
/// </summary>
/// <param name="client">Client object</param>
/// <returns>Is client blocked?</returns>
bool GetAndUpdateBlockedState(Client client)
{
if (client.blockedUntil != null && DateTime.UtcNow >= client.blockedUntil)
{
client.blockedUntil = null;
}
return client.blockedUntil != null;
}
/// <summary>
/// Send a message
/// </summary>
/// <param name="clientId">Client ID</param>
/// <param name="contents">Message contents</param>
/// <param name="needsToBeCensored">Does this message need to be censored?</param>
/// <returns>Was sending the message successful, can fail if client is blocked</returns>
public bool SendMessage(int clientId, string contents, bool needsToBeCensored)
{
lock (state.accessLock)
{
var client = FindClientById(clientId);
if (client == null)
{
return false;
}
if (GetAndUpdateBlockedState(client))
{
return false;
}
var message = new Message
{
id = NextId(),
clientId = clientId,
contents = contents,
needsToBeCensored = needsToBeCensored,
status = MessageStatus.WaitingForModerator,
sentAt = DateTime.UtcNow
};
state.messages.Add(message);
log.Info($"Client '{client.name}' ({client.id}) sent message '{contents}' ({message.id}). Needs to censored: {needsToBeCensored}");
}
return true;
}
/// <summary>
/// Get next message which isin't approved or rejected
/// </summary>
/// <returns>Optional message object</returns>
public ChatRoomContract.Message? GetNewMessage()
{
lock (state.accessLock)
{
foreach (var message in state.messages)
{
if (message.status != MessageStatus.WaitingForModerator) continue;
log.Info($"Message '{message.id}' given to moderator");
message.status = MessageStatus.GivenToModerator;
return new ChatRoomContract.Message{
id = message.id,
contents = message.contents,
needsToBeCensored = message.needsToBeCensored
};
}
}
return null;
}
/// <summary>
/// Approve a message
/// </summary>
/// <param name="messageId">Message ID</param>
public void ApproveMessage(int messageId)
{
lock (state.accessLock)
{
var message = FindMessageById(messageId);
if (message == null)
{
return;
}
if (message.status != MessageStatus.GivenToModerator)
{
return;
}
message.status = MessageStatus.Approved;
log.Info($"Message {message.id} was approved");
}
}
/// <summary>
/// Reject a message
/// </summary>
/// <param name="messageId">Message ID</param>
public void RejectMessage(int messageId)
{
lock (state.accessLock)
{
var message = FindMessageById(messageId);
if (message == null)
{
return;
}
if (message.status != MessageStatus.GivenToModerator)
{
return;
}
message.status = MessageStatus.Rejected;
log.Info($"Message {message.id} was rejected");
var client = FindClientById(message.clientId);
if (client != null && !GetAndUpdateBlockedState(client))
{
client.strikes++;
var rnd = new Random();
if (client.strikes > rnd.Next(0, 10))
{
log.Info($"Client '{client.name}' ({client.id}) was blocked for {client.strikes}s");
client.blockedUntil = DateTime.UtcNow.AddSeconds(client.strikes);
client.strikes = 0;
}
}
}
}
/// <summary>
/// Get number of strikes a client has
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Number of strikes</returns>
public int GetStrikes(int clientId)
{
lock (state.accessLock)
{
var client = FindClientById(clientId);
if (client == null)
{
return 0;
}
return client.strikes;
}
}
/// <summary>
/// Get timestamp until when the client is blocked
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Optional datetime object</returns>
public DateTime? GetBlockedUntil(int clientId)
{
lock (state.accessLock)
{
var client = FindClientById(clientId);
if (client == null)
{
return null;
}
return client.blockedUntil;
}
}
/// <summary>
/// Main loop for background thread. Used for deleting approved or rejected messages.
/// </summary>
public void BackgroundTask()
{
while (true)
{
lock (state.accessLock)
{
var now = DateTime.UtcNow;
int count = state.messages.RemoveAll(msg =>
(now - msg.sentAt).TotalSeconds > 5 &&
(msg.status == MessageStatus.Approved || msg.status == MessageStatus.Rejected)
);
log.Info($"Running periodic cleanup, removed {count} messages");
}
Thread.Sleep(10 * 1000);
}
}
}

View File

@ -0,0 +1,90 @@
namespace ChatRoom;
/// <summary>
/// Client information
/// </summary>
public class Client
{
/// <summary>
/// Client ID
/// </summary>
public int id;
/// <summary>
/// Client name, can be the same between multiple clients
/// </summary>
public string name;
/// <summary>
/// Number of strikes
/// </summary>
public int strikes = 0;
/// <summary>
/// Until when is this client blocked from sending messages
/// </summary>
public DateTime? blockedUntil = null;
}
/// <summary>
/// Describes the messages status/stage
/// </summary>
public enum MessageStatus
{
WaitingForModerator,
GivenToModerator,
Approved,
Rejected
}
/// <summary>
/// Message information
/// </summary>
public class Message
{
/// <summary>
/// Message ID
/// </summary>
public int id;
/// <summary>
/// Client ID
/// </summary>
public int clientId;
/// <summary>
/// Message contents
/// </summary>
public string contents;
/// <summary>
/// Does this message need to be censored?
/// </summary>
public bool needsToBeCensored;
/// <summary>
/// Message status/stage
/// </summary>
public MessageStatus status = MessageStatus.WaitingForModerator;
/// <summary>
/// When was this message sent
/// </summary>
public DateTime sentAt;
}
public class ChatRoomState
{
/// <summary>
/// Access lock.
/// </summary>
public readonly object accessLock = new object();
/// <summary>
/// Last unique ID value generated.
/// </summary>
public int lastUniqueId;
/// <summary>
/// List of all registered clients
/// </summary>
public List<Client> clients = new List<Client>();
/// <summary>
/// List of messages
/// </summary>
public List<Message> messages = new List<Message>();
}

View File

@ -0,0 +1,103 @@
using Microsoft.AspNetCore.Mvc;
namespace ChatRoom;
/// <summary>
/// Service. Class must be marked public, otherwise ASP.NET core runtime will not find it.
///
/// Look into FromXXX attributes if you need to map inputs to custom parts of HTTP request.
/// </summary>
[Route("chatRoom")]
[ApiController]
public class ChatRoomController : ControllerBase
{
/// <summary>
/// Service logic. This is created in Server.StartServer() and received through DI in constructor.
/// </summary>
private readonly ChatRoomLogic logic;
/// <summary>
/// Constructor
/// </summary>
/// <param name="logic">Logic to use. This will get passed through DI.</param>
public ChatRoomController(ChatRoomLogic logic)
{
this.logic = logic;
}
/// <summary>
/// Register client with a name
/// </summary>
/// <param name="name">Name of client, can be duplicate between clients</param>
/// <returns>Client ID</returns>
[HttpPost("/registerClient")]
public ActionResult<int> RegisterClient(string name)
{
return logic.RegisterClient(name);
}
/// <summary>
/// Get number of strikes a participant has
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Number of strikes</returns>
[HttpGet("/getStrikes")]
public ActionResult<int> GetStrikes(int clientId)
{
return logic.GetStrikes(clientId);
}
/// <summary>
/// Get timestamp until when the client is blocked
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Optional datetime object</returns>
[HttpGet("/getBlockedUntil")]
public ActionResult<DateTime?> GetBlockedUntil(int clientId)
{
return logic.GetBlockedUntil(clientId);
}
/// <summary>
/// Send a message, will be given to a moderator to be approved
/// </summary>
/// <param name="clientId">Client ID</param>
/// <param name="contents">Message contents</param>
/// <param name="needsToBeCensored">Does this message need to be censored?</param>
/// <returns>Was sending successful, can fail if user is blocked</returns>
[HttpPost("/sendMessage")]
public ActionResult<bool> SendMessage(int clientId, string contents, bool needsToBeCensored)
{
return logic.SendMessage(clientId, contents, needsToBeCensored);
}
/// <summary>
/// Get the next message which hasn't been approved or rejected
/// </summary>
/// <returns>Message object. Returns null if there is no message</returns>
[HttpGet("/getNewMessage")]
public ActionResult<ChatRoomContract.Message?> GetNewMessage()
{
return logic.GetNewMessage();
}
/// <summary>
/// Reject a message
/// </summary>
/// <param name="messageId">Message ID</param>
[HttpPost("/rejectMessage")]
public void RejectMessage(int messageId)
{
logic.RejectMessage(messageId);
}
/// <summary>
/// Approve a message
/// </summary>
/// <param name="messageId">Message ID</param>
[HttpPost("/approveMessage")]
public void ApproveMessage(int messageId)
{
logic.ApproveMessage(messageId);
}
}

View File

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

View File

@ -0,0 +1,126 @@
using NLog;
using System.Net;
using System.Reflection;
using System.Text.Json.Serialization;
namespace ChatRoom;
public class Server
{
/// <summary>
/// Logger for this class.
/// </summary>
Logger log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Program entry point.
/// </summary>
/// <param name="args">Command line arguments.</param>
public static void Main(string[] args)
{
var self = new Server();
self.Run(args);
}
/// <summary>
/// Program body.
/// </summary>
/// <param name="args">Command line arguments.</param>
private void Run(string[] args)
{
//configure logging
ConfigureLogging();
//indicate server is about to start
log.Info("Server is about to start");
//start the server
StartServer(args);
}
/// <summary>
/// Configure loggin subsystem.
/// </summary>
private void ConfigureLogging()
{
var config = new NLog.Config.LoggingConfiguration();
var console =
new NLog.Targets.ConsoleTarget("console")
{
Layout = @"${date:format=HH\:mm\:ss}|${level}| ${message} ${exception}"
};
config.AddTarget(console);
config.AddRuleForAllLevels(console);
LogManager.Configuration = config;
}
/// <summary>
/// Starts integrated server.
/// </summary>
/// <param name="args">Command line arguments.</param>
public void StartServer(string[] args)
{
//create web app builder
var builder = WebApplication.CreateBuilder(args);
//configure integrated server
builder.WebHost.ConfigureKestrel(opts => {
opts.Listen(IPAddress.Loopback, 5000);
});
//add and configure swagger documentation generator (http://127.0.0.1:5000/swagger/)
builder.Services.AddSwaggerGen(opts => {
//include code comments in swagger documentation
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
opts.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
});
//turn on support for web api controllers
builder.Services
.AddControllers()
.AddJsonOptions(opts => {
//this makes enumeration values to be strings instead of integers in opeanapi doc
opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
//add CORS policies
builder.Services.AddCors(cr => {
//allow everything from everywhere
cr.AddPolicy("allowAll", cp => {
cp.AllowAnyOrigin();
cp.AllowAnyMethod();
cp.AllowAnyHeader();
});
});
//publish the background logic as (an internal) service through dependency injection,
//otherwise it will not start until the first client calls into controller
builder.Services.AddSingleton(new ChatRoomLogic());
//build the server
var app = builder.Build();
//turn CORS policy on
app.UseCors("allowAll");
//turn on support for swagger doc web page
app.UseSwagger();
app.UseSwaggerUI();
//turn on request routing
app.UseRouting();
//configure routes
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}"
);
//run the server
app.Run();
// app.RunAsync(); //use this if you need to implement background processing in the main thread
}
}

View File

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

View File

@ -0,0 +1,961 @@
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
#nullable enable
#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
#pragma warning disable 612 // Disable "CS0612 '...' is obsolete"
#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null"
#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ...
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
#pragma warning disable 8603 // Disable "CS8603 Possible null reference return"
#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter"
#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type"
#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)."
namespace ChatRoomContract
{
using System = global::System;
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class ChatRoomClient : IChatRoomService
{
#pragma warning disable 8618
private string _baseUrl;
#pragma warning restore 8618
private System.Net.Http.HttpClient _httpClient;
private static System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings, true);
private Newtonsoft.Json.JsonSerializerSettings _instanceSettings;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public ChatRoomClient(string baseUrl, System.Net.Http.HttpClient httpClient)
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
BaseUrl = baseUrl;
_httpClient = httpClient;
Initialize();
}
private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}
public string BaseUrl
{
get { return _baseUrl; }
set
{
_baseUrl = value;
if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/"))
_baseUrl += '/';
}
}
protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } }
static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
partial void Initialize();
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
/// <summary>
/// Register client with a name
/// </summary>
/// <param name="name">Name of client, can be duplicate between clients</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task<int> RegisterClientAsync(string? name)
{
return RegisterClientAsync(name, System.Threading.CancellationToken.None);
}
/// <summary>
/// Register client with a name
/// </summary>
/// <param name="name">Name of client, can be duplicate between clients</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual int RegisterClient(string? name)
{
return System.Threading.Tasks.Task.Run(async () => await RegisterClientAsync(name, System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Register client with a name
/// </summary>
/// <param name="name">Name of client, can be duplicate between clients</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<int> RegisterClientAsync(string? name, System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain");
request_.Method = new System.Net.Http.HttpMethod("POST");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "registerClient"
urlBuilder_.Append("registerClient");
urlBuilder_.Append('?');
if (name != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("name")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
urlBuilder_.Length--;
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<int>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>
/// Get number of strikes a participant has
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task<int> GetStrikesAsync(int? clientId)
{
return GetStrikesAsync(clientId, System.Threading.CancellationToken.None);
}
/// <summary>
/// Get number of strikes a participant has
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual int GetStrikes(int clientId)
{
return System.Threading.Tasks.Task.Run(async () => await GetStrikesAsync(clientId, System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Get number of strikes a participant has
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<int> GetStrikesAsync(int? clientId, System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "getStrikes"
urlBuilder_.Append("getStrikes");
urlBuilder_.Append('?');
if (clientId != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("clientId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(clientId, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
urlBuilder_.Length--;
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<int>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>
/// Get timestamp until when the client is blocked
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task<System.DateTime?> GetBlockedUntilAsync(int? clientId)
{
return GetBlockedUntilAsync(clientId, System.Threading.CancellationToken.None);
}
/// <summary>
/// Get timestamp until when the client is blocked
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.DateTime? GetBlockedUntil(int clientId)
{
return System.Threading.Tasks.Task.Run(async () => await GetBlockedUntilAsync(clientId, System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Get timestamp until when the client is blocked
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<System.DateTime?> GetBlockedUntilAsync(int? clientId, System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "getBlockedUntil"
urlBuilder_.Append("getBlockedUntil");
urlBuilder_.Append('?');
if (clientId != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("clientId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(clientId, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
urlBuilder_.Length--;
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<System.DateTimeOffset>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object.DateTime;
}
else if (status_ == 204)
{
return null;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>
/// Send a message, will be given to a moderator to be approved
/// </summary>
/// <param name="clientId">Client ID</param>
/// <param name="contents">Message contents</param>
/// <param name="needsToBeCensored">Does this message need to be censored?</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task<bool> SendMessageAsync(int? clientId, string? contents, bool? needsToBeCensored)
{
return SendMessageAsync(clientId, contents, needsToBeCensored, System.Threading.CancellationToken.None);
}
/// <summary>
/// Send a message, will be given to a moderator to be approved
/// </summary>
/// <param name="clientId">Client ID</param>
/// <param name="contents">Message contents</param>
/// <param name="needsToBeCensored">Does this message need to be censored?</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual bool SendMessage(int clientId, string contents, bool needsToBeCensored)
{
return System.Threading.Tasks.Task.Run(async () => await SendMessageAsync(clientId, contents, needsToBeCensored, System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Send a message, will be given to a moderator to be approved
/// </summary>
/// <param name="clientId">Client ID</param>
/// <param name="contents">Message contents</param>
/// <param name="needsToBeCensored">Does this message need to be censored?</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<bool> SendMessageAsync(int? clientId, string? contents, bool? needsToBeCensored, System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain");
request_.Method = new System.Net.Http.HttpMethod("POST");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "sendMessage"
urlBuilder_.Append("sendMessage");
urlBuilder_.Append('?');
if (clientId != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("clientId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(clientId, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
if (contents != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("contents")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(contents, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
if (needsToBeCensored != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("needsToBeCensored")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(needsToBeCensored, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
urlBuilder_.Length--;
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<bool>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>
/// Get the next message which hasn't been approved or rejected
/// </summary>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task<Message?> GetNewMessageAsync()
{
return GetNewMessageAsync(System.Threading.CancellationToken.None);
}
/// <summary>
/// Get the next message which hasn't been approved or rejected
/// </summary>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual Message? GetNewMessage()
{
return System.Threading.Tasks.Task.Run(async () => await GetNewMessageAsync(System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Get the next message which hasn't been approved or rejected
/// </summary>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<Message?> GetNewMessageAsync(System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain"));
var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "getNewMessage"
urlBuilder_.Append("getNewMessage");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<Message>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else if (status_ == 204)
{
return null;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>
/// Reject a message
/// </summary>
/// <param name="messageId">Message ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task RejectMessageAsync(int? messageId)
{
return RejectMessageAsync(messageId, System.Threading.CancellationToken.None);
}
/// <summary>
/// Reject a message
/// </summary>
/// <param name="messageId">Message ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual void RejectMessage(int messageId)
{
System.Threading.Tasks.Task.Run(async () => await RejectMessageAsync(messageId, System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Reject a message
/// </summary>
/// <param name="messageId">Message ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task RejectMessageAsync(int? messageId, System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "rejectMessage"
urlBuilder_.Append("rejectMessage");
urlBuilder_.Append('?');
if (messageId != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("messageId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(messageId, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
urlBuilder_.Length--;
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>
/// Approve a message
/// </summary>
/// <param name="messageId">Message ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task ApproveMessageAsync(int? messageId)
{
return ApproveMessageAsync(messageId, System.Threading.CancellationToken.None);
}
/// <summary>
/// Approve a message
/// </summary>
/// <param name="messageId">Message ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual void ApproveMessage(int messageId)
{
System.Threading.Tasks.Task.Run(async () => await ApproveMessageAsync(messageId, System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Approve a message
/// </summary>
/// <param name="messageId">Message ID</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task ApproveMessageAsync(int? messageId, System.Threading.CancellationToken cancellationToken)
{
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "approveMessage"
urlBuilder_.Append("approveMessage");
urlBuilder_.Append('?');
if (messageId != null)
{
urlBuilder_.Append(System.Uri.EscapeDataString("messageId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(messageId, System.Globalization.CultureInfo.InvariantCulture))).Append('&');
}
urlBuilder_.Length--;
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
protected struct ObjectResponseResult<T>
{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}
public T Object { get; }
public string Text { get; }
}
public bool ReadResponseAsString { get; set; }
protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Threading.CancellationToken cancellationToken)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T)!, string.Empty);
}
if (ReadResponseAsString)
{
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody!, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
}
}
else
{
try
{
using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody!, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception);
}
}
}
private string ConvertToString(object? value, System.Globalization.CultureInfo cultureInfo)
{
if (value == null)
{
return "";
}
if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
if (field != null)
{
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}
var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
return converted == null ? string.Empty : converted;
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[])value);
}
else if (value is string[])
{
return string.Join(",", (string[])value);
}
else if (value.GetType().IsArray)
{
var valueArray = (System.Array)value;
var valueTextArray = new string[valueArray.Length];
for (var i = 0; i < valueArray.Length; i++)
{
valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo);
}
return string.Join(",", valueTextArray);
}
var result = System.Convert.ToString(value, cultureInfo);
return result == null ? "" : result;
}
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class ApiException : System.Exception
{
public int StatusCode { get; private set; }
public string? Response { get; private set; }
public System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }
public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Exception? innerException)
: base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException)
{
StatusCode = statusCode;
Response = response;
Headers = headers;
}
public override string ToString()
{
return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString());
}
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class ApiException<TResult> : ApiException
{
public TResult Result { get; private set; }
public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, TResult result, System.Exception? innerException)
: base(message, statusCode, response, headers, innerException)
{
Result = result;
}
}
}
#pragma warning restore 108
#pragma warning restore 114
#pragma warning restore 472
#pragma warning restore 612
#pragma warning restore 1573
#pragma warning restore 1591
#pragma warning restore 8073
#pragma warning restore 3016
#pragma warning restore 8603
#pragma warning restore 8604
#pragma warning restore 8625

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,74 @@
namespace ChatRoomContract;
/// <summary>
/// Minimal message description
/// </summary>
public class Message
{
/// <summary>
/// Message ID
/// </summary>
public int id { get; set; }
/// <summary>
/// Message contents
/// </summary>
public string contents { get; set; }
/// <summary>
/// Does this message need to be censored?
/// </summary>
public bool needsToBeCensored { get; set; }
}
/// <summary>
/// Chat room service contract
/// </summary>
public interface IChatRoomService
{
/// <summary>
/// Register client with a name
/// </summary>
/// <param name="name">Name of client, can be duplicate between clients</param>
/// <returns>Client ID</returns>
int RegisterClient(string name);
/// <summary>
/// Get number of strikes a participant has
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Number of strikes</returns>
int GetStrikes(int clientId);
/// <summary>
/// Get timestamp until when the client is blocked
/// </summary>
/// <param name="clientId">Client ID</param>
/// <returns>Optional datetime object</returns>
DateTime? GetBlockedUntil(int clientId);
/// <summary>
/// Send a message, will be given to a moderator to be approved
/// </summary>
/// <param name="clientId">Client ID</param>
/// <param name="contents">Message contents</param>
/// <param name="needsToBeCensored">Does this message need to be censored?</param>
/// <returns>Was sending successful, can fail if user is blocked</returns>
bool SendMessage(int clientId, string contents, bool needsToBeCensored);
/// <summary>
/// Get the next message which hasn't been approved or rejected
/// </summary>
/// <returns>Message object. Returns null if there is no message</returns>
Message? GetNewMessage();
/// <summary>
/// Reject a message
/// </summary>
/// <param name="messageId">Message ID</param>
void RejectMessage(int messageId);
/// <summary>
/// Approve a message
/// </summary>
/// <param name="messageId">Message ID</param>
void ApproveMessage(int messageId);
}

43
Lab2-rest/Lab2-rest.sln Normal file
View File

@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35208.52
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatRoom", "ChatRoom\ChatRoom.csproj", "{5F24CB9F-866F-4104-A6FB-A60371E6A85F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatRoomContract", "ChatRoomContract\ChatRoomContract.csproj", "{CC5134F2-1127-4AF2-8CAF-1EFEAF31F5C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moderator", "Moderator\Moderator.csproj", "{572058F8-3C35-463C-95E9-A056A872FE36}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Participant", "Participant\Participant.csproj", "{E2193712-FABC-4447-A291-AE0C29E80DD8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5F24CB9F-866F-4104-A6FB-A60371E6A85F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F24CB9F-866F-4104-A6FB-A60371E6A85F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F24CB9F-866F-4104-A6FB-A60371E6A85F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F24CB9F-866F-4104-A6FB-A60371E6A85F}.Release|Any CPU.Build.0 = Release|Any CPU
{CC5134F2-1127-4AF2-8CAF-1EFEAF31F5C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC5134F2-1127-4AF2-8CAF-1EFEAF31F5C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC5134F2-1127-4AF2-8CAF-1EFEAF31F5C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC5134F2-1127-4AF2-8CAF-1EFEAF31F5C0}.Release|Any CPU.Build.0 = Release|Any CPU
{572058F8-3C35-463C-95E9-A056A872FE36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{572058F8-3C35-463C-95E9-A056A872FE36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{572058F8-3C35-463C-95E9-A056A872FE36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{572058F8-3C35-463C-95E9-A056A872FE36}.Release|Any CPU.Build.0 = Release|Any CPU
{E2193712-FABC-4447-A291-AE0C29E80DD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2193712-FABC-4447-A291-AE0C29E80DD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2193712-FABC-4447-A291-AE0C29E80DD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2193712-FABC-4447-A291-AE0C29E80DD8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {39207399-CA34-4BBB-BE63-E7BBCD0B52C5}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,92 @@
using ChatRoomContract;
using NLog;
using Bogus;
namespace Moderator;
internal class Moderator
{
/// <summary>
/// Logger for this class.
/// </summary>
Logger log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Configures logging subsystem.
/// </summary>
private void ConfigureLogging()
{
var config = new NLog.Config.LoggingConfiguration();
var console =
new NLog.Targets.ConsoleTarget("console")
{
Layout = @"${date:format=HH\:mm\:ss}|${level}| ${message} ${exception}"
};
config.AddTarget(console);
config.AddRuleForAllLevels(console);
LogManager.Configuration = config;
}
private void RunConnection(IChatRoomService chatRoom)
{
var faker = new Faker("en");
var name = faker.Name.FullName();
int clientId = chatRoom.RegisterClient(name);
log.Info($"Registered with client id {clientId}");
Console.Title = $"Moderator | {name} | {clientId}";
while (true)
{
var message = chatRoom.GetNewMessage();
if (message != null)
{
log.Info($"Checking message ({message.id}): {message.contents}");
Thread.Sleep(500);
if (message.needsToBeCensored)
{
chatRoom.RejectMessage(message.id);
}
else
{
chatRoom.ApproveMessage(message.id);
}
}
Thread.Sleep(1 * 1000);
}
}
private void Run()
{
ConfigureLogging();
while (true)
{
var client = new ChatRoomClient("http://127.0.0.1:5000", new HttpClient());
try
{
RunConnection(client);
}
catch (Exception e)
{
//log whatever exception to console
log.Warn(e, "Unhandled exception caught. Will restart main loop.");
//prevent console spamming
Thread.Sleep(2000);
}
}
}
static void Main(string[] args)
{
var self = new Moderator();
self.Run();
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bogus" Version="35.6.1" />
<PackageReference Include="NLog" Version="5.3.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ChatRoomContract\ChatRoomContract.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,86 @@
using ChatRoomContract;
using NLog;
using Bogus;
namespace Participant;
internal class Participant
{
/// <summary>
/// Logger for this class.
/// </summary>
Logger log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Configures logging subsystem.
/// </summary>
private void ConfigureLogging()
{
var config = new NLog.Config.LoggingConfiguration();
var console =
new NLog.Targets.ConsoleTarget("console")
{
Layout = @"${date:format=HH\:mm\:ss}|${level}| ${message} ${exception}"
};
config.AddTarget(console);
config.AddRuleForAllLevels(console);
LogManager.Configuration = config;
}
private void RunConnection(IChatRoomService chatRoom)
{
var faker = new Faker("en");
var rnd = new Random();
var name = faker.Name.FullName();
int clientId = chatRoom.RegisterClient(name);
log.Info($"Registered with client id {clientId}");
while (true)
{
int strikes = chatRoom.GetStrikes(clientId);
Console.Title = $"Participant | {name} | {clientId} | {strikes} Strikes";
var message = string.Join(" ", faker.Lorem.Words(5));
bool needsToBeCensored = rnd.Next(0, 100) > 50;
if (chatRoom.SendMessage(clientId, message, needsToBeCensored)) {
log.Info("Sent message");
} else {
log.Info("Failed to send message, blocked");
}
Thread.Sleep(2 * 1000);
}
}
private void Run()
{
ConfigureLogging();
while (true)
{
var client = new ChatRoomClient("http://127.0.0.1:5000", new HttpClient());
try
{
RunConnection(client);
}
catch (Exception e)
{
//log whatever exception to console
log.Warn(e, "Unhandled exception caught. Will restart main loop.");
//prevent console spamming
Thread.Sleep(2000);
}
}
}
static void Main(string[] args)
{
var self = new Participant();
self.Run();
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bogus" Version="35.6.1" />
<PackageReference Include="NLog" Version="5.3.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ChatRoomContract\ChatRoomContract.csproj" />
</ItemGroup>
</Project>