diff --git a/examples/hash/.gitignore b/examples/hash/.gitignore new file mode 100644 index 000000000..ed730df34 --- /dev/null +++ b/examples/hash/.gitignore @@ -0,0 +1,3 @@ +dotnet.* +func.yaml +project.lock.json diff --git a/examples/hash/README.md b/examples/hash/README.md new file mode 100644 index 000000000..c03d67f18 --- /dev/null +++ b/examples/hash/README.md @@ -0,0 +1,53 @@ +# Using dotnet with functions + +Make sure you downloaded and installed [dotnet](https://www.microsoft.com/net/core). Now create an empty dotnet project in the directory of your function: + +```bash +dotnet new +``` + +By default dotnet creates a ```Program.cs``` file with a main method. To make it work with IronFunction's `fn` tool please rename it to ```func.cs```. +Now change the code as you desire to do whatever magic you need it to do. Once done you can now create an iron function out of it. + +## Creating an IronFunction +Simply run + +```bash +fn init / +``` + +This will create the ```func.yaml``` file required by functions, which can be built by running: + +## Push to docker +```bash +fn push +``` + +This will create a docker image and push the image to docker. + +## Publishing to IronFunctions + +```bash +fn routes create +``` + +This creates a full path in the form of `http://:/r//` + + +## Testing + +```bash +fn run +``` + +## Calling + +```bash +fn call +``` + +or + +```bash +curl http://:/r// +``` \ No newline at end of file diff --git a/examples/hash/func.cs b/examples/hash/func.cs new file mode 100755 index 000000000..7e848a8f5 --- /dev/null +++ b/examples/hash/func.cs @@ -0,0 +1,65 @@ +using System; +using System.Text; +using System.Security.Cryptography; +using System.IO; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + // if nothing is being piped in, then exit + if (!IsPipedInput()) + return; + + var input = Console.In.ReadToEnd(); + var stream = DownloadRemoteImageFile(input); + var hash = CreateChecksum(stream); + Console.WriteLine(hash); + } + + private static bool IsPipedInput() + { + try + { + bool isKey = Console.KeyAvailable; + return false; + } + catch + { + return true; + } + } + private static byte[] DownloadRemoteImageFile(string uri) + { + + var request = System.Net.WebRequest.CreateHttp(uri); + var response = request.GetResponseAsync().Result; + var stream = response.GetResponseStream(); + using (MemoryStream ms = new MemoryStream()) + { + stream.CopyTo(ms); + return ms.ToArray(); + } + } + private static string CreateChecksum(byte[] stream) + { + using (var md5 = MD5.Create()) + { + var hash = md5.ComputeHash(stream); + var sBuilder = new StringBuilder(); + + // Loop through each byte of the hashed data + // and format each one as a hexadecimal string. + for (int i = 0; i < hash.Length; i++) + { + sBuilder.Append(hash[i].ToString("x2")); + } + + // Return the hexadecimal string. + return sBuilder.ToString(); + } + } + } +} diff --git a/examples/hash/project.json b/examples/hash/project.json new file mode 100755 index 000000000..861cef47d --- /dev/null +++ b/examples/hash/project.json @@ -0,0 +1,19 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "debugType": "portable", + "emitEntryPoint": true + }, + "dependencies": {}, + "frameworks": { + "netcoreapp1.1": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.1.0" + } + }, + "imports": "dnxcore50" + } + } +} diff --git a/fn/common.go b/fn/common.go index 4b847f712..3de02401f 100644 --- a/fn/common.go +++ b/fn/common.go @@ -132,6 +132,7 @@ var acceptableFnRuntimes = map[string]string{ "ruby": "iron/ruby", "scala": "iron/scala", "rust": "corey/rust-alpine", + "dotnet": "microsoft/dotnet:runtime", } const tplDockerfile = `FROM {{ .BaseImage }} diff --git a/fn/init.go b/fn/init.go index 7b831f59a..38b966a2c 100644 --- a/fn/init.go +++ b/fn/init.go @@ -28,6 +28,7 @@ var ( ".rb": "ruby", ".py": "python", ".rs": "rust", + ".cs": "dotnet", } fnInitRuntimes []string diff --git a/fn/langs/base.go b/fn/langs/base.go index bc0117ffb..7bf1a36c8 100644 --- a/fn/langs/base.go +++ b/fn/langs/base.go @@ -15,6 +15,8 @@ func GetLangHelper(lang string) (LangHelper, error) { return &PythonHelper{}, nil case "rust": return &RustLangHelper{}, nil + case "dotnet": + return &DotNetLangHelper{}, nil } return nil, fmt.Errorf("No language helper found for %v", lang) } diff --git a/fn/langs/dotnet.go b/fn/langs/dotnet.go new file mode 100644 index 000000000..d943595d5 --- /dev/null +++ b/fn/langs/dotnet.go @@ -0,0 +1,42 @@ +package langs + +import ( + "fmt" + "os" + "os/exec" +) + +type DotNetLangHelper struct{} + +func (lh *DotNetLangHelper) Entrypoint() string { + return "dotnet dotnet.dll" +} + +func (lh *DotNetLangHelper) HasPreBuild() bool { + return true +} + +// PreBuild for Go builds the binary so the final image can be as small as possible +func (lh *DotNetLangHelper) PreBuild() error { + wd, err := os.Getwd() + if err != nil { + return err + } + + cmd := exec.Command( + "docker", "run", + "--rm", "-v", + wd+":/dotnet", "-w", "/dotnet", "microsoft/dotnet", + "/bin/sh", "-c", "dotnet restore && dotnet publish -c release -b /tmp -o .", + ) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + if err := cmd.Run(); err != nil { + return fmt.Errorf("error running docker build: %v", err) + } + return nil +} + +func (lh *DotNetLangHelper) AfterBuild() error { + return nil +}