Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: v3 .NET #144

Merged
merged 16 commits into from
Jun 8, 2023
Merged
Prev Previous commit
Next Next commit
Fix dotnet tests
  • Loading branch information
Meldiron committed Jan 31, 2023
commit c0ea80295de4600c20d78a8db25f86ab35fb5102
6 changes: 3 additions & 3 deletions runtimes/dotnet-6.0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ To learn more about runtimes, visit [Structure](https://github.com/open-runtimes

```bash
mkdir dotnet-or && cd dotnet-or
printf "public async Task<RuntimeOutput> Main(RuntimeContext context) => context.res.Json(new() {{ \"n\", new System.Random().NextDouble() }} );" > Index.cs
printf "public async Task<RuntimeOutput> Main(RuntimeContext Context) => Context.Res.Json(new() {{ \"n\", new System.Random().NextDouble() }} );" > Index.cs
```

2. Build the code:
Expand Down Expand Up @@ -70,8 +70,8 @@ You can also make changes to the example code and apply the changes with the `do
- When writing function for this runtime, ensure it is named `Main`. An example of this is:

```cs
public async Task<RuntimeOutput> Main(RuntimeContext context) =>
context.res.send("Hello Open Runtimes 👋");
public async Task<RuntimeOutput> Main(RuntimeContext Context) =>
Context.Res.Send("Hello Open Runtimes 👋");
```

- To handle dependencies, you need to have `csproj` file containing the `PackageReferences` you desire. Dependencies will be automatically cached and installed, so you don't need to include the `.nuget` folder in your function.
Expand Down
8 changes: 4 additions & 4 deletions runtimes/dotnet-6.0/example/Index.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

static readonly HttpClient http = new();

public async Task<RuntimeOutput> Main(RuntimeContext context)
public async Task<RuntimeOutput> Main(RuntimeContext Context)
{
string id = "1";

if (!(context.req.body is String))
if (!(Context.Req.Body is String))
{
Dictionary<string, object> body = (Dictionary<string, object>) context.req.body;
Dictionary<string, object> body = (Dictionary<string, object>) Context.Req.Body;
id = body.TryGetValue("id", out var value) ? (string) value : "1";
}

var response = await http.GetStringAsync($"https://jsonplaceholder.typicode.com/todos/{id}");
var todo = JsonConvert.DeserializeObject<Dictionary<string, object>>(response, settings: null);

return context.res.json(new()
return Context.Res.Json(new()
{
{ "message", "Hello Open Runtimes 👋" },
{ "todo", todo }
Expand Down
35 changes: 20 additions & 15 deletions runtimes/dotnet-6.0/src/CustomResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,34 @@ namespace DotNetRuntime
{
class CustomResponse : IResult
{
private readonly string _body;
private readonly int _statusCode;
private readonly Dictionary<string, string> _headers;
private readonly string _Body;
abnegate marked this conversation as resolved.
Show resolved Hide resolved
private readonly int _StatusCode;
private readonly Dictionary<string, string> _Headers;

public CustomResponse(string body, int statusCode, Dictionary<string, string>? headers = null)
public CustomResponse(string Body, int StatusCode, Dictionary<string, string>? Headers = null)
{
if(headers == null) {
headers = new Dictionary<string,string>();
if(Headers == null)
{
Headers = new Dictionary<string,string>();
}

_body = body;
_statusCode = statusCode;
_headers = headers;
_Body = Body;
_StatusCode = StatusCode;
_Headers = Headers;
}

public Task ExecuteAsync(HttpContext httpContext)
public Task ExecuteAsync(HttpContext HttpContext)
{
string contentType = _headers.TryGetValue("content-type", out var contentTypeValue) ? (string) contentTypeValue : "plain/text";
string contentType = _Headers.TryGetValue("content-type", out var contentTypeValue) ? (string) contentTypeValue : "plain/text";

httpContext.Response.StatusCode = _statusCode;
httpContext.Response.ContentType = contentType;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(_body);
return httpContext.Response.WriteAsync(_body);
foreach (var Entry in _Headers)
{
HttpContext.Response.Headers.Add(Entry.Key, Entry.Value);
}
HttpContext.Response.StatusCode = _StatusCode;
HttpContext.Response.ContentType = contentType;
HttpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(_Body);
return HttpContext.Response.WriteAsync(_Body);
}
}
}
97 changes: 52 additions & 45 deletions runtimes/dotnet-6.0/src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,80 +11,87 @@
app.MapMethods("/{*path}", new[] { "GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD", "TRACE" }, Execute);
app.Run();

static async Task<IResult> Execute(HttpRequest request)
static async Task<IResult> Execute(HttpRequest Request)
{
string secret = request.Headers.TryGetValue("x-open-runtimes-secret", out var secretValue) ? (string) secretValue : "";
if(secret != Environment.GetEnvironmentVariable("OPEN_RUNTIMES_SECRET")) {
string Secret = Request.Headers.TryGetValue("x-open-runtimes-secret", out var SecretValue) ? (string) SecretValue : "";
if(Secret != Environment.GetEnvironmentVariable("OPEN_RUNTIMES_SECRET"))
{
return new CustomResponse("Unauthorized. Provide correct \"x-open-runtimes-secret\" header.", 500);
}

StreamReader reader = new StreamReader(request.Body);
string rawBody = await reader.ReadToEndAsync();
object body = rawBody;
Dictionary<string, string> headers = new Dictionary<string, string>();
string method = request.Method;
string url = request.Path + request.QueryString;
StreamReader Reader = new StreamReader(Request.Body);
Meldiron marked this conversation as resolved.
Show resolved Hide resolved
string RawBody = await Reader.ReadToEndAsync();
object Body = RawBody;
Dictionary<string, string> Headers = new Dictionary<string, string>();
string Method = Request.Method;
string Url = Request.Path + Request.QueryString;

foreach (var entry in request.Headers) {
var header = entry.Key;
var value = entry.Value;
header = header.ToLower();
foreach (var Entry in Request.Headers)
{
var Header = Entry.Key;
var Value = Entry.Value;
Header = Header.ToLower();

if(!(header.StartsWith("x-open-runtimes-"))) {
headers.Add(header, value);
if(!(Header.StartsWith("x-open-runtimes-")))
{
Headers.Add(Header, Value);
}
}

string contentType = request.Headers.TryGetValue("content-type", out var contentTypeValue) ? (string) contentTypeValue : "";
if(contentType.Contains("application/json")) {
body = JsonConvert.DeserializeObject<Dictionary<string, object>>(rawBody);
string ContentType = Request.Headers.TryGetValue("content-type", out var ContentTypeValue) ? (string) ContentTypeValue : "";
if(ContentType.Contains("application/json"))
{
Body = JsonConvert.DeserializeObject<Dictionary<string, object>>(RawBody);
}

RuntimeRequest contextRequest = new RuntimeRequest(rawBody, body, headers, method, url);
RuntimeResponse contextResponse = new RuntimeResponse();
RuntimeContext context = new RuntimeContext(contextRequest, contextResponse);
RuntimeRequest ContextRequest = new RuntimeRequest(RawBody, Body, Headers, Method, Url);
RuntimeResponse ContextResponse = new RuntimeResponse();
RuntimeContext Context = new RuntimeContext(ContextRequest, ContextResponse);

var customstd = new StringBuilder();
var customstdWriter = new StringWriter(customstd);
Console.SetOut(customstdWriter);
Console.SetError(customstdWriter);
var Customstd = new StringBuilder();
var CustomstdWriter = new StringWriter(Customstd);
Console.SetOut(CustomstdWriter);
Console.SetError(CustomstdWriter);

RuntimeOutput? output = null;
RuntimeOutput? Output = null;

try
{
var codeWrapper = new Wrapper();
output = await codeWrapper.Main(context);
var CodeWrapper = new Wrapper();
Output = await CodeWrapper.Main(Context);
}
catch (Exception e)
{
context.error(e.ToString());
output = context.res.send("", 500, new Dictionary<string,string>());
Context.Error(e.ToString());
Output = Context.Res.Send("", 500, new Dictionary<string,string>());
}

if(output == null) {
context.error("Return statement missing. return context.res.empty() if no response is expected.");
output = context.res.send("", 500, new Dictionary<string,string>());
if(Output == null)
{
Context.Error("Return statement missing. return Context.Res.Empty() if no response is expected.");
Output = Context.Res.Send("", 500, new Dictionary<string,string>());
}

var outputHeaders = new Dictionary<string, string>();
var OutputHeaders = new Dictionary<string, string>();

foreach (var entry in output.headers) {
var header = entry.Key;
var value = entry.Value;
header = header.ToLower();
foreach (var Entry in Output.Headers)
{
var Header = Entry.Key;
var Value = Entry.Value;
Header = Header.ToLower();

if(!(header.StartsWith("x-open-runtimes-"))) {
outputHeaders.Add(header, value);
if(!(Header.StartsWith("x-open-runtimes-")))
{
OutputHeaders.Add(Header, Value);
}
}

if(String.IsNullOrEmpty(customstd.ToString())) {
context.log("Unsupported log noticed. Use context.log() or context.error() for logging.");
if(!String.IsNullOrEmpty(Customstd.ToString())) {
Context.Log("Unsupported log noticed. Use Context.Log() or Context.Error() for logging.");
}

outputHeaders.Add("x-open-runtimes-logs", System.Web.HttpUtility.UrlEncode(String.Join('\n', context._logs)));
outputHeaders.Add("x-open-runtimes-errors", System.Web.HttpUtility.UrlEncode(String.Join('\n', context._errors)));
OutputHeaders.Add("x-open-runtimes-logs", System.Web.HttpUtility.UrlEncode(String.Join("\n", Context._Logs.Cast<string>().ToArray())));
OutputHeaders.Add("x-open-runtimes-errors", System.Web.HttpUtility.UrlEncode(String.Join("\n", Context._Errors.Cast<string>().ToArray())));

return new CustomResponse(output.body, output.statusCode, outputHeaders);
return new CustomResponse(Output.Body, Output.StatusCode, OutputHeaders);
}
24 changes: 13 additions & 11 deletions runtimes/dotnet-6.0/src/RuntimeContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@ namespace DotNetRuntime
{
public class RuntimeContext
{
public RuntimeRequest req { get; set; }
public RuntimeResponse res { get; set; }
public RuntimeRequest Req { get; set; }
public RuntimeResponse Res { get; set; }

public ArrayList _logs = new ArrayList();
public ArrayList _errors = new ArrayList();
public ArrayList _Logs = new ArrayList();
public ArrayList _Errors = new ArrayList();

public RuntimeContext(RuntimeRequest req, RuntimeResponse res)
public RuntimeContext(RuntimeRequest Req, RuntimeResponse Res)
{
this.req = req;
this.res = res;
this.Req = Req;
this.Res = Res;
}

public void log(object message) {
this._logs.Add(message.ToString());
public void Log(object Message)
{
this._Logs.Add(Message.ToString());
}

public void error(object message) {
this._errors.Add(message.ToString());
public void Error(object Message)
{
this._Errors.Add(Message.ToString());
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions runtimes/dotnet-6.0/src/RuntimeOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ namespace DotNetRuntime
{
public class RuntimeOutput
{
public string body { get; set; }
public int statusCode { get; set; }
public Dictionary<string, string> headers { get; set; }
public string Body { get; set; }
public int StatusCode { get; set; }
public Dictionary<string, string> Headers { get; set; }

public RuntimeOutput(string body, int statusCode, Dictionary<string, string> headers)
public RuntimeOutput(string Body, int StatusCode, Dictionary<string, string> Headers)
{
this.body = body;
this.statusCode = statusCode;
this.headers = headers;
this.Body = Body;
this.StatusCode = StatusCode;
this.Headers = Headers;
}
}
}
Expand Down
22 changes: 11 additions & 11 deletions runtimes/dotnet-6.0/src/RuntimeRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ namespace DotNetRuntime
{
public class RuntimeRequest
{
public string rawBody { get; set; }
public object body { get; set; }
public Dictionary<string, string> headers { get; set; }
public string method { get; set; }
public string url { get; set; }
public string RawBody { get; set; }
public object Body { get; set; }
public Dictionary<string, string> Headers { get; set; }
public string Method { get; set; }
public string Url { get; set; }

public RuntimeRequest(string rawBody, object body, Dictionary<string, string> headers, string method, string url)
public RuntimeRequest(string RawBody, object Body, Dictionary<string, string> Headers, string Method, string Url)
{
this.rawBody = rawBody;
this.body = body;
this.headers = headers;
this.method = method;
this.url = url;
this.RawBody = RawBody;
this.Body = Body;
this.Headers = Headers;
this.Method = Method;
this.Url = Url;
}
}
}
Expand Down
34 changes: 18 additions & 16 deletions runtimes/dotnet-6.0/src/RuntimeResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,39 @@ namespace DotNetRuntime;

public class RuntimeResponse
{
public RuntimeOutput send(string body, int statusCode = 200, Dictionary<string, string>? headers = null)
public RuntimeOutput Send(string Body, int StatusCode = 200, Dictionary<string, string>? Headers = null)
{
if(headers == null) {
headers = new Dictionary<string,string>();
if(Headers == null)
{
Headers = new Dictionary<string,string>();
}

return new RuntimeOutput(body, statusCode, headers);
return new RuntimeOutput(Body, StatusCode, Headers);
}

public RuntimeOutput json(Dictionary<string, object?> json, int statusCode = 200, Dictionary<string, string>? headers = null)
public RuntimeOutput Json(Dictionary<string, object?> Json, int StatusCode = 200, Dictionary<string, string>? Headers = null)
{
if(headers == null) {
headers = new Dictionary<string,string>();
if(Headers == null)
{
Headers = new Dictionary<string,string>();
}

headers.Add("content-type", "application/json");
return this.send(JsonSerializer.Serialize(json), statusCode, headers);
Headers.Add("content-type", "application/json");
return this.Send(JsonSerializer.Serialize(Json), StatusCode, Headers);
}

public RuntimeOutput empty()
public RuntimeOutput Empty()
{
return this.send("", 204, new Dictionary<string, string>());
return this.Send("", 204, new Dictionary<string, string>());
}

public RuntimeOutput redirect(String url, int statusCode = 200, Dictionary<string, string>? headers = null)
public RuntimeOutput Redirect(String Url, int StatusCode = 301, Dictionary<string, string>? Headers = null)
{
if(headers == null) {
headers = new Dictionary<string,string>();
if(Headers == null) {
Headers = new Dictionary<string,string>();
}

headers.Add("location", url);
return this.send("", statusCode, headers);
Headers.Add("location", Url);
return this.Send("", StatusCode, Headers);
}
}
6 changes: 3 additions & 3 deletions runtimes/python-3.10/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def redirect(self, url, statusCode = 301, headers = {}):
return self.send('', statusCode, headers)

class Request:
rawBody = None
raw_body = None
body = None
headers = None
method = None
Expand Down Expand Up @@ -90,8 +90,8 @@ def handler(u_path):
if query:
path += '?' + query

context.req.rawBody = request.get_data(as_text=True)
context.req.body = context.req.rawBody
context.req.raw_body = request.get_data(as_text=True)
context.req.body = context.req.raw_body
context.req.method = request.method
context.req.url = path
context.req.headers = {}
Expand Down
Loading