diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9feacfd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+*.swp
+*.*~
+project.lock.json
+.DS_Store
+*.pyc
+nupkg/
+
+# Visual Studio Code
+
+# Rider
+.idea
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+msbuild.log
+msbuild.err
+msbuild.wrn
+
+# Visual Studio 2015
+.vs/
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..14a9546
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,27 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/AuroraCradle/bin/Debug/netcoreapp3.1/aurora-cradle-sharp.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..736a20a
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,42 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/AuroraCradle/aurora-cradle-sharp.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/aurora-cradle-sharp.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "${workspaceFolder}/aurora-cradle-sharp.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
diff --git a/AuroraCradle.test/AuroraSignal.test.csproj b/AuroraCradle.test/AuroraSignal.test.csproj
new file mode 100644
index 0000000..8aa4944
--- /dev/null
+++ b/AuroraCradle.test/AuroraSignal.test.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net5.0
+
+ false
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/AuroraCradle.test/CursorList.test.cs b/AuroraCradle.test/CursorList.test.cs
new file mode 100644
index 0000000..4a99d96
--- /dev/null
+++ b/AuroraCradle.test/CursorList.test.cs
@@ -0,0 +1,163 @@
+using Xunit;
+using Aurora.Services.Signal;
+using Aurora.Cursor;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AuroraCradle.test
+{
+ public class CursorListTest
+ {
+ [Theory()]
+ [InlineData(Aurora.Cursor.SortDirection.Asc)]
+ [InlineData(Aurora.Cursor.SortDirection.Desc)]
+ public void CursorListSortOnStringValue(Aurora.Cursor.SortDirection direction)
+ {
+ CursorList list = new CursorList();
+ list.Add(new Party() { Name = "asdf", Id = Faker.RandomNumber.Next().ToString() });
+ list.Add(new Party() { Name = "bsdf", Id = Faker.RandomNumber.Next().ToString() });
+ list.Add(new Party() { Name = "csdf", Id = Faker.RandomNumber.Next().ToString() });
+
+ CursorResult result = new Cursor(ref list)
+ .WithSort(item => item.Value.Name, direction)
+ .GetNextPage();
+
+ if (direction == Aurora.Cursor.SortDirection.Desc)
+ {
+ Assert.Collection(result.Result,
+ item => item.Name.Equals("asdf"),
+ item => item.Name.Equals("bsdf"),
+ item => item.Name.Equals("csdf"));
+ }
+ else
+ {
+ Assert.Collection(result.Result,
+ item => item.Name.Equals("csdf"),
+ item => item.Name.Equals("bsdf"),
+ item => item.Name.Equals("asdf"));
+
+ }
+ }
+
+ [Theory()]
+ [InlineData(2)]
+ [InlineData(10)]
+ [InlineData(49)]
+ [InlineData(51)]
+ [InlineData(-1)]
+ public void CursorListSizeTest(int size)
+ {
+ int numOfItems = 50;
+ CursorList list = new CursorList();
+
+ // Add items to cursor list
+ for (int i = 0; i < numOfItems; i++)
+ {
+ list.Add(new Party()
+ {
+ Name = string.Join(" ",
+ Faker.Lorem.Words(2)),
+ Id = Faker.RandomNumber.Next().ToString()
+ });
+ }
+
+ Cursor cursor = new Cursor(ref list);
+ if (size < 0)
+ {
+ Assert.Throws(() =>
+ {
+ cursor.WithSize(size).GetNextPage();
+ });
+ }
+ else if (size > numOfItems)
+ {
+ CursorResult res = cursor.WithSize(size).GetNextPage();
+ Assert.Equal(res.Result.Count, numOfItems);
+ }
+ else if (size < numOfItems && size > 0)
+ {
+ CursorResult res = cursor.WithSize(size).GetNextPage();
+ Assert.Equal(res.Result.Count, size);
+ }
+ }
+
+ [Theory()]
+ [InlineData(2)]
+ [InlineData(10)]
+ [InlineData(3)]
+ public void CursorPaginationTest(int pageSize)
+ {
+ int numOfItems = 50;
+ CursorList list = new CursorList();
+
+ // Add items to cursor list
+ for (int i = 0; i < numOfItems; i++)
+ {
+ list.Add(new Party()
+ {
+ Name = string.Join(" ",
+ Faker.Lorem.Words(2)),
+ Id = Faker.RandomNumber.Next().ToString()
+ });
+ }
+
+ string pageToken = null;
+ Cursor cursor = new Cursor(ref list);
+ List pagedResults = new List();
+ while (pageToken != string.Empty)
+ {
+ CursorResult res = cursor
+ .WithSize(pageSize)
+ .WithNextPageToken(pageToken)
+ .GetNextPage();
+
+ pagedResults.AddRange(res.Result);
+ pageToken = res.NextPageToken;
+ }
+
+ Assert.Equal(pagedResults.Count, numOfItems);
+ }
+
+ [Fact()]
+
+ public void CursorPaginationWithSortTest()
+ {
+ int numOfItems = 50;
+ CursorList cursorList = new CursorList();
+
+ // Add items to cursor list
+ for (int i = 0; i < numOfItems; i++)
+ {
+ cursorList.Add(new Party()
+ {
+ Name = string.Join(" ",
+ Faker.Lorem.Words(2)),
+ Id = Faker.RandomNumber.Next().ToString()
+ });
+ }
+
+ var orderedList = cursorList.ToList().OrderBy(item => item.Value.Name).ToList().ConvertAll(item => item.Value);
+
+ string pageToken = null;
+ Cursor cursor = new Cursor(ref cursorList);
+ List pagedResults = new List();
+ while (pageToken != string.Empty)
+ {
+ CursorResult res = cursor
+ .WithSize(10)
+ .WithSort(item => item.Value.Name, Aurora.Cursor.SortDirection.Asc)
+ .WithNextPageToken(pageToken)
+ .GetNextPage();
+
+ pagedResults.AddRange(res.Result);
+ pageToken = res.NextPageToken;
+ }
+
+ var list = cursorList.ToList();
+ for (int i = 0; i < orderedList.Count; i++)
+ {
+ Assert.Equal(orderedList[i], pagedResults[i]);
+ }
+ }
+ }
+}
diff --git a/AuroraCradle/Src/Augments/Party.cs b/AuroraCradle/Src/Augments/Party.cs
new file mode 100644
index 0000000..52c697f
--- /dev/null
+++ b/AuroraCradle/Src/Augments/Party.cs
@@ -0,0 +1,9 @@
+using Aurora.Cursor;
+
+namespace Aurora.Services.Signal
+{
+ public partial class Party : ICursorObject
+ {
+ }
+}
+
diff --git a/AuroraCradle/Src/Cursor/Cursor.cs b/AuroraCradle/Src/Cursor/Cursor.cs
new file mode 100644
index 0000000..9a60991
--- /dev/null
+++ b/AuroraCradle/Src/Cursor/Cursor.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+#nullable enable
+namespace Aurora.Cursor
+{
+ public enum SortDirection
+ {
+ Asc,
+ Desc,
+ }
+
+ public class Cursor where T : ICursorObject
+ {
+ private CursorList _list;
+
+ private string? _previousPageToken;
+ private string? _nextPageToken;
+ private int _pageSize;
+ private Func, string> _sortDelgate;
+ private SortDirection _direction;
+ public Cursor(ref CursorList list)
+ {
+ this._list = list;
+ this._previousPageToken = string.Empty;
+ this._nextPageToken = string.Empty;
+ this._pageSize = 10;
+ this._sortDelgate = delegate (KeyValuePair item)
+ {
+ return item.Key;
+ };
+ }
+
+ public CursorResult GetNextPage()
+ {
+ if (this._pageSize < 0)
+ {
+ throw new InvalidOperationException("Page Size must be greater than zero");
+ }
+ List> tmpList;
+
+ // Sort reference list
+ if (this._direction == SortDirection.Desc)
+ {
+ tmpList = this._list.OrderByDescending(this._sortDelgate).ToList();
+
+ }
+ else
+ {
+ tmpList = this._list.OrderBy(this._sortDelgate).ToList();
+ }
+
+ if (tmpList == null)
+ {
+ throw new System.NullReferenceException();
+ }
+
+ int startIdx = 0;
+ if (!string.IsNullOrEmpty(this._nextPageToken))
+ {
+ // TODO find another way to index into the list that's not a regular array search
+ startIdx = tmpList.FindIndex(item => item.Key == this._nextPageToken) + 1;
+ }
+
+ int adjustedSize = this._pageSize;
+ if (startIdx + this._pageSize > tmpList.Count)
+ {
+ adjustedSize = this._pageSize - ((startIdx + _pageSize) - tmpList.Count);
+ }
+
+
+ List> selection = new List>();
+ if (adjustedSize != 0)
+ {
+ selection = tmpList.GetRange(startIdx, adjustedSize);
+ }
+
+ return new CursorResult
+ {
+ NextPageToken = this._pageSize == selection.Count ? selection[selection.Count - 1].Key : string.Empty,
+ PrevPageToken = string.Empty,
+ Count = this._list.Count,
+ Result = selection.ConvertAll(item => item.Value)
+ };
+ }
+
+ public CursorResult GetPreviousPage()
+ {
+ throw new NotImplementedException();
+ }
+
+ public Cursor WithNextPageToken(string nextPageToken)
+ {
+ this._nextPageToken = nextPageToken;
+ return this;
+ }
+
+ public Cursor WithPreviousPageToken(string prevPageToken)
+ {
+ this._previousPageToken = prevPageToken;
+ return this;
+ }
+
+ public Cursor WithSort(Func, string> sortDelegate, SortDirection direction)
+ {
+ this._sortDelgate = sortDelegate;
+ this._direction = direction;
+ return this;
+ }
+
+ public Cursor WithSort(string key, SortDirection direction)
+ {
+ this._sortDelgate = (item) => key;
+ this._direction = direction;
+ return this;
+ }
+
+ public Cursor WithSize(int size)
+ {
+ this._pageSize = size;
+ return this;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/AuroraCradle/Src/Cursor/CursorList.cs b/AuroraCradle/Src/Cursor/CursorList.cs
new file mode 100644
index 0000000..0dcbf04
--- /dev/null
+++ b/AuroraCradle/Src/Cursor/CursorList.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+using System.Collections;
+using System;
+using System.Linq;
+using Aurora.Utils;
+
+#nullable enable
+namespace Aurora.Cursor
+{
+
+ public class CursorList : SortedList where T : ICursorObject
+ {
+
+ public CursorList()
+ {
+ }
+
+ public CursorList Add(T item)
+ {
+ string id = item.Id;
+ if (item.Id == null)
+ {
+ id = HashUtil.GetHash(new string[] { item.GetHashCode().ToString() }).ToString();
+ item.Id = id;
+ }
+ bool res = this.TryAdd(id, item);
+
+ if (res == false)
+ {
+ throw new System.Exception("Failed to add item to cursor list");
+ }
+ return this;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/AuroraCradle/Src/Cursor/CursorObject.cs b/AuroraCradle/Src/Cursor/CursorObject.cs
new file mode 100644
index 0000000..cca1779
--- /dev/null
+++ b/AuroraCradle/Src/Cursor/CursorObject.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Aurora.Cursor
+{
+ public interface ICursorObject
+ {
+ string Id { get; set; }
+ }
+}
diff --git a/AuroraCradle/Src/Cursor/CursorResult.cs b/AuroraCradle/Src/Cursor/CursorResult.cs
new file mode 100644
index 0000000..ab50c6a
--- /dev/null
+++ b/AuroraCradle/Src/Cursor/CursorResult.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+namespace Aurora.Cursor
+{
+ public class CursorResult
+ {
+ public CursorResult()
+ {
+ Result = new List();
+ }
+
+ public CursorResult(CursorResult cpy)
+ {
+ NextPageToken = cpy.NextPageToken;
+ PrevPageToken = cpy.PrevPageToken;
+ Result = cpy.Result;
+ Count = cpy.Count;
+ }
+
+ public string NextPageToken { get; set; }
+ public string PrevPageToken { get; set; }
+ public List Result { get; set; }
+ public int Count { get; set; }
+ }
+}
diff --git a/AuroraCradle/Src/Program.cs b/AuroraCradle/Src/Program.cs
new file mode 100644
index 0000000..6ffeaba
--- /dev/null
+++ b/AuroraCradle/Src/Program.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+
+namespace Aurora
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ // Additional configuration is required to successfully run gRPC on macOS.
+ // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
diff --git a/AuroraCradle/Src/Protos/signal.proto b/AuroraCradle/Src/Protos/signal.proto
new file mode 100644
index 0000000..078630d
--- /dev/null
+++ b/AuroraCradle/Src/Protos/signal.proto
@@ -0,0 +1,167 @@
+syntax = "proto3";
+
+option csharp_namespace = "Aurora.Services.Signal";
+
+package signal;
+
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/empty.proto";
+
+
+service Signal {
+ //**************
+ //Party Resource
+ //**************
+ //Get Party
+ rpc ListParties(ListPartiesRequest) returns (ListPartiesResponse);
+
+ rpc GetParty(GetPartyRequest) returns (Party);
+
+ rpc UpdateParty(UpdatePartyRequest) returns (Party);
+
+ rpc CreateParty(CreatePartyRequest) returns (Party);
+
+ rpc DeleteParty(DeletePartyRequest) returns (google.protobuf.Empty);
+
+
+ //***************************
+ //EventSubscriptions Resource
+ //***************************
+ //List
+ rpc ListEventSubscriptions(ListEventSubscriptionsRequest) returns (ListEventSubscriptionsResponse);
+
+ //Create
+ rpc SubscribeToEvent(EventSubscriptionRequest) returns (EventSubscription);
+
+ //Delete
+ rpc DeleteEventSubscription(DeleteEventSubscriptionRequest) returns (google.protobuf.Empty);
+
+ //CUSTOM: Create EventSubscription List
+ rpc SubscribeToEvents(EventSubscriptionListRequest) returns (EventSubscriptionListResponse);
+
+ //CUSTOM: Delete all
+ rpc DeleteAllEventSubscriptions(DeleteAllEventSubscriptionsRequest) returns (google.protobuf.Empty);
+
+ //*****
+ //Event
+ //*****
+ //Get
+ rpc GetEventStream(GetEventsRequest) returns (stream BaseEvent) {};
+}
+
+message Party {
+ //The resource name of the party
+ string name = 1;
+ string id = 2;
+ string display_name = 3;
+ string description = 4;
+ string host_ip = 5;
+ google.protobuf.Timestamp created_on = 6;
+}
+
+message PartyListItem {
+ string name = 1;
+ string id = 2;
+}
+
+message ListPartiesRequest {
+ int32 page_size = 1;
+ string page_token = 2;
+ string order_by = 3;
+ SortDirection order_direction = 4;
+}
+
+enum SortDirection {
+ Asc = 0;
+ Desc = 1;
+}
+
+message ListPartiesResponse {
+ repeated PartyListItem parties = 1;
+ string next_page_token = 2;
+}
+
+message GetPartyRequest {
+ string party_id = 1;
+}
+
+message CreatePartyRequest {
+ string party_id = 1;
+ Party party = 2;
+}
+
+message DeletePartyRequest {
+ string party_id = 1;
+}
+
+message UpdatePartyRequest {
+ Party party = 1;
+ google.protobuf.FieldMask update_mask = 2;
+}
+
+/* Event Types */
+enum EventType {
+ NewPartiesAvailable = 0;
+}
+
+message NewPartiesAvailableEvent {
+}
+
+message BaseEvent {
+ //Resource name of the event ?
+ string name = 1;
+ EventType event_type = 2;
+ oneof derivedEvent {
+ NewPartiesAvailableEvent new_parties_available_event = 3;
+ }
+}
+
+message EventSubscription {
+ EventType type = 2;
+}
+
+message ListEventSubscriptionsRequest {
+ //Resource name of parent to the subscription list (The member)
+ string parent = 1;
+ int32 page_size = 2;
+ string page_token = 3;
+}
+
+message ListEventSubscriptionsResponse {
+ repeated EventSubscription subscriptions = 1;
+ string next_page_token = 2;
+}
+
+message EventSubscriptionRequest {
+ //Resource name of the parent to the subscription list (The member)
+ string parent = 1;
+ EventSubscription event_subscription = 2;
+}
+
+message DeleteEventSubscriptionRequest {
+ //Resource name of the subscription to delete
+ string parent = 1;
+ EventType type = 2;
+}
+
+message EventSubscriptionListRequest {
+ //Resource name of the parent to the subscription list (The member)
+ string parent = 1;
+ repeated EventSubscription event_subscriptions = 2;
+}
+
+message EventSubscriptionListResponse {
+ repeated EventSubscription event_subscriptions = 1;
+}
+
+message DeleteAllEventSubscriptionsRequest {
+ //Resource name of the parent to the subscription list (the member)
+ string parent = 1;
+}
+
+message GetEventsRequest {
+ //Resource name of the parent to the event stream (the member)
+ string parent = 1;
+}
diff --git a/AuroraCradle/Src/Services/Signal/Events.cs b/AuroraCradle/Src/Services/Signal/Events.cs
new file mode 100644
index 0000000..41e7034
--- /dev/null
+++ b/AuroraCradle/Src/Services/Signal/Events.cs
@@ -0,0 +1,7 @@
+namespace Aurora.Services.Signal
+{
+ public partial class SignalService : Signal.SignalBase
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/AuroraCradle/Src/Services/Signal/Party.cs b/AuroraCradle/Src/Services/Signal/Party.cs
new file mode 100644
index 0000000..c044cde
--- /dev/null
+++ b/AuroraCradle/Src/Services/Signal/Party.cs
@@ -0,0 +1,79 @@
+using System.Threading.Tasks;
+using Google.Protobuf.WellKnownTypes;
+using Grpc.Core;
+using Aurora.Cursor;
+using Microsoft.Extensions.Logging;
+
+namespace Aurora.Services.Signal
+{
+ public partial class SignalService : Signal.SignalBase
+ {
+ private CursorList _partyList;
+
+ public override Task CreateParty(CreatePartyRequest request, ServerCallContext context)
+ {
+ Party party = new Party(request.Party);
+ _partyList.Add(party);
+
+ this._logger.LogInformation(string.Format("Added party with name: ${0} to parties", party.Name));
+
+ return Task.FromResult(party);
+ }
+
+ public override Task DeleteParty(DeletePartyRequest request, ServerCallContext context)
+ {
+ if (this._partyList.ContainsKey(request.PartyId))
+ {
+ this._partyList.Remove(request.PartyId);
+ }
+
+ this._logger.LogInformation(string.Format("Deleted party with id: ${0} to parties", request.PartyId));
+ return Task.FromResult(new Empty());
+ }
+
+ public override Task ListParties(ListPartiesRequest request, ServerCallContext context)
+ {
+ Cursor cursor = new Cursor(ref this._partyList);
+
+ Aurora.Cursor.SortDirection direction = Aurora.Cursor.SortDirection.Asc;
+ if (request.OrderDirection == SortDirection.Desc)
+ {
+ direction = Aurora.Cursor.SortDirection.Desc;
+ }
+
+ CursorResult res = cursor
+ .WithSort(request.OrderBy, direction)
+ .WithNextPageToken(request.PageToken)
+ .WithSize(request.PageSize)
+ .GetNextPage();
+
+ ListPartiesResponse response = new ListPartiesResponse()
+ {
+ NextPageToken = res.NextPageToken
+ };
+ response.Parties.AddRange(res.Result.ConvertAll(party => new PartyListItem()
+ {
+ Name = party.Name,
+ Id = party.Id
+ }));
+ return Task.FromResult(response);
+ }
+
+ public override Task GetParty(GetPartyRequest request, ServerCallContext context)
+ {
+ Party party = new Party();
+
+ if (this._partyList.ContainsKey(request.PartyId))
+ {
+ this._partyList.TryGetValue(request.PartyId, out party);
+ }
+
+ return Task.FromResult(party);
+ }
+
+ public override Task UpdateParty(UpdatePartyRequest request, ServerCallContext context)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/AuroraCradle/Src/Services/Signal/SignalService.cs b/AuroraCradle/Src/Services/Signal/SignalService.cs
new file mode 100644
index 0000000..3561c59
--- /dev/null
+++ b/AuroraCradle/Src/Services/Signal/SignalService.cs
@@ -0,0 +1,17 @@
+using Microsoft.Extensions.Logging;
+using Aurora.Cursor;
+
+namespace Aurora.Services.Signal
+{
+ public partial class SignalService : Signal.SignalBase
+ {
+ private readonly ILogger _logger;
+
+ public SignalService(ILogger logger)
+ {
+ _logger = logger;
+ this._partyList = new CursorList();
+ }
+
+ }
+}
diff --git a/AuroraCradle/Src/Startup.cs b/AuroraCradle/Src/Startup.cs
new file mode 100644
index 0000000..57b8520
--- /dev/null
+++ b/AuroraCradle/Src/Startup.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Aurora.Services.Signal;
+
+namespace Aurora
+{
+ public class Startup
+ {
+ // This method gets called by the runtime. Use this method to add services to the container.
+ // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddGrpc();
+ services.AddGrpcReflection();
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+
+ }
+
+ app.UseRouting();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapGrpcService();
+
+ if (env.IsDevelopment())
+ {
+ endpoints.MapGrpcReflectionService();
+ }
+ endpoints.MapGet("/", async context =>
+ {
+ await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
+ });
+ });
+ }
+ }
+}
diff --git a/AuroraCradle/Src/Utils/HashUtil.cs b/AuroraCradle/Src/Utils/HashUtil.cs
new file mode 100644
index 0000000..0644870
--- /dev/null
+++ b/AuroraCradle/Src/Utils/HashUtil.cs
@@ -0,0 +1,25 @@
+using System.Security.Cryptography;
+using System.Text;
+using System;
+
+namespace Aurora.Utils
+{
+ public class HashUtil
+ {
+ public static Guid GetHash(string[] inputs)
+ {
+ string input = "";
+ foreach (string str in inputs)
+ {
+ input += str;
+ }
+
+ byte[] stringbytes = Encoding.UTF8.GetBytes(input);
+ byte[] hashedBytes = new System.Security.Cryptography
+ .SHA1CryptoServiceProvider()
+ .ComputeHash(stringbytes);
+ Array.Resize(ref hashedBytes, 16);
+ return new Guid(hashedBytes);
+ }
+ }
+}
diff --git a/AuroraCradle/appsettings.Development.json b/AuroraCradle/appsettings.Development.json
new file mode 100644
index 0000000..fe20c40
--- /dev/null
+++ b/AuroraCradle/appsettings.Development.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "System": "Information",
+ "Grpc": "Information",
+ "Microsoft": "Information"
+ }
+ }
+}
diff --git a/AuroraCradle/appsettings.json b/AuroraCradle/appsettings.json
new file mode 100644
index 0000000..df549a7
--- /dev/null
+++ b/AuroraCradle/appsettings.json
@@ -0,0 +1,15 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*",
+ "Kestrel": {
+ "EndpointDefaults": {
+ "Protocols": "Http1"
+ }
+ }
+}
diff --git a/AuroraCradle/aurora-cradle-sharp.csproj b/AuroraCradle/aurora-cradle-sharp.csproj
new file mode 100644
index 0000000..1e350d2
--- /dev/null
+++ b/AuroraCradle/aurora-cradle-sharp.csproj
@@ -0,0 +1,16 @@
+
+
+
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e230517
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# aurora-cradle-sharp
+
diff --git a/workspace.code-workspace b/workspace.code-workspace
new file mode 100644
index 0000000..1e373c0
--- /dev/null
+++ b/workspace.code-workspace
@@ -0,0 +1,15 @@
+{
+ "folders": [
+ {
+ "path": "."
+ }
+ ],
+"settings": {
+ "files.exclude": {
+ "**/obj": true
+ },
+ "dotnet-test-explorer.testProjectPath": "./AuroraCradle.test",
+ "editor.formatOnSave": true,
+ "editor.defaultFormatter": "ms-dotnettools.csharp"
+}
+}