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
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ env:
SERVER_PROCESS="DotNetRuntime.dll"
IMAGE=openruntimes/dotnet:${VERSION}-6.0
ARCH=linux/amd64,linux/arm64
TEST_SCRIPT=tests.sh
TEST_SCRIPT=tests-v3.sh


notifications:
Expand Down
4 changes: 2 additions & 2 deletions runtimes/dotnet-6.0/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
INTERNAL_RUNTIME_KEY=secret-key
INTERNAL_RUNTIME_ENTRYPOINT=Index.cs
OPEN_RUNTIMES_SECRET=secret-key
OPEN_RUNTIMES_ENTRYPOINT=Index.cs
24 changes: 0 additions & 24 deletions runtimes/dotnet-6.0/Example/Index.cs

This file was deleted.

56 changes: 35 additions & 21 deletions runtimes/dotnet-6.0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,25 @@ To learn more about runtimes, visit [Structure](https://github.com/open-runtimes

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

2. Build the code:

```bash
docker run -e INTERNAL_RUNTIME_ENTRYPOINT=Index.cs --rm --interactive --tty --volume $PWD:/usr/code openruntimes/dotnet:v3-6.0 sh /usr/local/src/build.sh
docker run -e OPEN_RUNTIMES_ENTRYPOINT=Index.cs --rm --interactive --tty --volume $PWD:/usr/code openruntimes/dotnet:v3-6.0 sh /usr/local/src/build.sh
```

3. Spin-up open-runtime:

```bash
docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key -e INTERNAL_RUNTIME_ENTRYPOINT=Index.cs --rm --interactive --tty --volume $PWD/code.tar.gz:/tmp/code.tar.gz:ro openruntimes/dotnet:v3-6.0 sh /usr/local/src/start.sh
docker run -p 3000:3000 -e OPEN_RUNTIMES_SECRET=secret-key -e OPEN_RUNTIMES_ENTRYPOINT=Index.cs --rm --interactive --tty --volume $PWD/code.tar.gz:/tmp/code.tar.gz:ro openruntimes/dotnet:v3-6.0 sh /usr/local/src/start.sh
```

4. In new terminal window, execute function:

```bash
curl -H "X-Internal-Challenge: secret-key" -H "Content-Type: application/json" -X POST http:https://localhost:3000/ -d '{"payload": "{}"}'
curl -H "x-open-runtimes-secret: secret-key" -X GET http:https://localhost:3000/
```

Output `{"n":0.7232589496628183}` with random float will be displayed after the execution.
Expand Down Expand Up @@ -58,36 +58,50 @@ docker-compose up -d
4. Execute the function:

```bash
curl -H "X-Internal-Challenge: secret-key" -H "Content-Type: application/json" -X POST http:https://localhost:3000/ -d '{"payload": "{}"}'
curl -H "x-open-runtimes-secret: secret-key" -H "Content-Type: application/json" -X POST http:https://localhost:3000/ -d '{"id": "4"}'
```

You can now send `POST` request to `http:https://localhost:3000`. Make sure you have header `x-internal-challenge: secret-key`. If your function expects any parameters, you can pass an optional JSON body like so: `{ "payload":"{}" }`.
You can now send `POST` request to `http:https://localhost:3000`. Make sure you have header `x-open-runtimes-secret: secret-key`.

You can also make changes to the example code and apply the changes with the `docker-compose restart` command.

## Notes

- The `res` parameter has two methods:

- `Send()`: Send a string response to the client.
- `Json()`: Send a JSON response to the client.

You can respond with `Json()` by providing object:
- When writing function for this runtime, ensure it is named `Main` and is inside `Handler` class. An example of this is:

```cs
public async Task<RuntimeResponse> Main(RuntimeRequest req, RuntimeResponse res) =>
res.Json(new()
{
{ "message" , "Hello Open Runtimes 👋" },
{ "variables", req.Variables },
{ "headers", req.Headers },
{ "payload", req.Payload }
});
namespace DotNetRuntime;

public class Handler {
public async Task<RuntimeOutput> Main(RuntimeContext Context) =>
Context.Res.Send("Hello Open Runtimes 👋");
}
```

- Your entrypoint code must start with `namespace DotNetRuntime;`.

- 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.

- The default entrypoint is `Index.cs`. If your entrypoint differs, make sure to configure it using `INTERNAL_RUNTIME_ENTRYPOINT` environment variable, for instance, `INTERNAL_RUNTIME_ENTRYPOINT=src/App.cs`.
- The default entrypoint is `Index.cs`. If your entrypoint differs, make sure to configure it using `OPEN_RUNTIMES_ENTRYPOINT` environment variable, for instance, `OPEN_RUNTIMES_ENTRYPOINT=src/App.cs`.

- F# can be used in .NET runtime:

```fs
namespace DotNetRuntime

type Handler()=
[YOUR_CODE]
```

- Visual Basic can be used in .NET runtime:

```vb
Namespace DotNetRuntime
Public Class Handler
[YOUR_CODE]
End Class
End Namespace
```

## Authors

Expand Down
70 changes: 0 additions & 70 deletions runtimes/dotnet-6.0/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,6 @@ build() {
break
done


case ${INTERNAL_RUNTIME_ENTRYPOINT##*.} in
cs) write_cs_wrapper ;;
fs) write_fs_wrapper ;;
vb) write_vb_wrapper ;;
esac

# Remove the user code file (copy)
rm "${INTERNAL_RUNTIME_ENTRYPOINT}"

abnegate marked this conversation as resolved.
Show resolved Hide resolved
# Build the executable
cd /usr/local/src
dotnet publish DotNetRuntime.csproj -c Release
Expand All @@ -47,64 +37,4 @@ build() {
tar -czf /usr/code/code.tar.gz .
}

write_cs_wrapper() {
# Read user code and collect usings
USINGS=""
while read line; do
case "${line}" in using*)
USINGS="${USINGS}${line}
"
esac
done < "$INTERNAL_RUNTIME_ENTRYPOINT"
CODE="$(sed /using*/d "$INTERNAL_RUNTIME_ENTRYPOINT")"

# Wrap the user code in a class
echo "${USINGS}
namespace DotNetRuntime;
public class Wrapper {
${CODE}
}
" > Wrapper.cs
}

write_fs_wrapper() {
# Read user code and collect opens
OPENS=""
while read line; do
case "${line}" in open*)
OPENS="${OPENS}${line}
"
esac
done < "$INTERNAL_RUNTIME_ENTRYPOINT"
CODE="$(sed /open*/d "$INTERNAL_RUNTIME_ENTRYPOINT" | sed 's/^/ /')"
# Wrap the user code in a class
echo "namespace DotNetRuntime
${OPENS}
type Wrapper()=
${CODE}
" > Wrapper.fs

cat Wrapper.fs
}

write_vb_wrapper() {
# Read user code and collect imports
IMPORTS=""
while read line; do
case "${line}" in Imports*)
IMPORTS="${IMPORTS}${line}
"
esac
done < "$INTERNAL_RUNTIME_ENTRYPOINT"
CODE="$(sed /using*/d "$INTERNAL_RUNTIME_ENTRYPOINT")"

# Wrap the user code in a class
echo "${IMPORTS}
Namespace DotNetRuntime
Public Class Wrapper
${CODE}
End Class
End Namespace" > Wrapper.vb
}

build
4 changes: 2 additions & 2 deletions runtimes/dotnet-6.0/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ services:
ports:
- 3000:3000
environment:
- INTERNAL_RUNTIME_KEY
- INTERNAL_RUNTIME_ENTRYPOINT
- OPEN_RUNTIMES_SECRET
- OPEN_RUNTIMES_ENTRYPOINT
volumes:
- ./example/:/usr/code:rw
command: sh -c "sh /usr/local/src/build.sh && cp /usr/code/code.tar.gz /tmp/code.tar.gz && sh /usr/local/src/start.sh"
27 changes: 27 additions & 0 deletions runtimes/dotnet-6.0/example/Index.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace DotNetRuntime;

using Newtonsoft.Json;

public class Handler {
static readonly HttpClient http = new();

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

if (!(Context.Req.Body is String))
{
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()
{
{ "message", "Hello Open Runtimes 👋" },
{ "todo", todo }
});
}
}
37 changes: 37 additions & 0 deletions runtimes/dotnet-6.0/src/CustomResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Text;

namespace DotNetRuntime
{
class CustomResponse : IResult
{
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)
{
if(Headers == null)
{
Headers = new Dictionary<string,string>();
}

_Body = Body;
_StatusCode = StatusCode;
_Headers = Headers;
}

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

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);
}
}
}
Loading