Example #1
0
        public async Task <Run> HandleRequest(HttpContext httpContext)
        {
            await _initSemaphoreSlim.WaitAsync();

            try
            {
                if (Initialized)
                {
                    await httpContext.Response.WriteError("Cannot initialize the action more than once.");

                    Console.Error.WriteLine("Cannot initialize the action more than once.");
                    return(new Run(Type, Method, Constructor, AwaitableMethod));
                }

                string  body        = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
                JObject inputObject = JObject.Parse(body);
                if (!inputObject.ContainsKey("value"))
                {
                    await httpContext.Response.WriteError("Missing main/no code to execute.");

                    return(null);
                }

                JToken message = inputObject["value"];

                if (message["main"] == null || message["binary"] == null || message["code"] == null)
                {
                    await httpContext.Response.WriteError("Missing main/no code to execute.");

                    return(null);
                }

                string main = message["main"].ToString();

                bool binary = message["binary"].ToObject <bool>();

                if (!binary)
                {
                    await httpContext.Response.WriteError("code must be binary (zip file).");

                    return(null);
                }

                string[] mainParts = main.Split("::");
                if (mainParts.Length != 3)
                {
                    await httpContext.Response.WriteError("main required format is \"Assembly::Type::Function\".");

                    return(null);
                }

                string base64Zip = message["code"].ToString();
                string tempPath  = Path.Combine(Environment.CurrentDirectory, Guid.NewGuid().ToString());
                string tempFile  = Path.GetTempFileName();
                await File.WriteAllBytesAsync(tempFile, Convert.FromBase64String(base64Zip));

                try
                {
                    System.IO.Compression.ZipFile.ExtractToDirectory(tempFile, tempPath);
                }
                catch (Exception)
                {
                    await httpContext.Response.WriteError("Unable to decompress package.");

                    return(null);
                }
                finally
                {
                    File.Delete(tempFile);
                }

                Environment.CurrentDirectory = tempPath;

                string assemblyFile = $"{mainParts[0]}.dll";

                string assemblyPath = Path.Combine(tempPath, assemblyFile);

                if (!File.Exists(assemblyPath))
                {
                    await httpContext.Response.WriteError($"Unable to locate requested assembly (\"{assemblyFile}\").");

                    return(null);
                }

                try
                {
                    Assembly assembly = Assembly.LoadFrom(assemblyPath);
                    Type = assembly.GetType(mainParts[1]);
                    if (Type == null)
                    {
                        await httpContext.Response.WriteError($"Unable to locate requested type (\"{mainParts[1]}\").");

                        return(null);
                    }
                    Method      = Type.GetMethod(mainParts[2]);
                    Constructor = Type.GetConstructor(Type.EmptyTypes);
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine(ex.ToString());
                    await httpContext.Response.WriteError(ex.Message
#if DEBUG
                                                          + ", " + ex.StackTrace
#endif
                                                          );

                    return(null);
                }

                if (Method == null)
                {
                    await httpContext.Response.WriteError($"Unable to locate requested method (\"{mainParts[2]}\").");

                    return(null);
                }

                if (Constructor == null)
                {
                    await httpContext.Response.WriteError($"Unable to locate appropriate constructor for (\"{mainParts[1]}\").");

                    return(null);
                }

                Initialized = true;

                AwaitableMethod = (Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null);

                return(new Run(Type, Method, Constructor, AwaitableMethod));
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.StackTrace);
                await httpContext.Response.WriteError(ex.Message
#if DEBUG
                                                      + ", " + ex.StackTrace
#endif
                                                      );

                Startup.WriteLogMarkers();
                return(null);
            }
            finally
            {
                _initSemaphoreSlim.Release();
            }
        }