Пример #1
0
        public void CanCompileCustomScriptContext()
        {
            CSharpScriptContext ctx = new CSharpScriptContext();

            ctx.Script = "System.Console.WriteLine(\"monkey\");";
            ctx.Execute(new Type[] {}, new Type[] {});
        }
Пример #2
0
        public static void __Start__(CSharpScriptContext context)
        {
            context.Dispatch.AddHandler <SPlayMoviePacket>((client, direction, packet, flags) =>
            {
                return(false);
            });

            context.Dispatch.AddHandler <CEndMoviePacket>((client, direction, packet, flags) =>
            {
                return(false);
            });

            context.Log.Basic("Started no cutscenes script");
        }
Пример #3
0
        public static void __Start__(CSharpScriptContext context)
        {
            _context = context;

            context.Dispatch.AddHandler <CCheckVersionPacket>((client, direction, packet, flags) =>
            {
                foreach (var ver in packet.Versions)
                {
                    _context.Log.Info("Client reported version: {0}", ver.Value);
                }

                return(true);
            });

            context.Log.Basic("Started example script");
        }
Пример #4
0
 public static void __Stop__(CSharpScriptContext context)
 {
     context.Log.Basic("Stopped example script");
 }
Пример #5
0
 public static void __Stop__(CSharpScriptContext context)
 {
     context.Log.Basic("Stopped no cutscenes script");
 }
Пример #6
0
        public void Configure(
            IApplicationBuilder app,
            IWebHostEnvironment env,
            WebAppConfiguration webAppConfig,
            ProcessStore.IProcessStoreWriter processStoreWriter,
            Func <DateTimeOffset> getDateTimeOffset)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            var nextHttpRequestIndex = 0;

            var            cyclicReductionStoreLock            = new object();
            DateTimeOffset?cyclicReductionStoreLastTime        = null;
            var            cyclicReductionStoreDistanceSeconds = (int)TimeSpan.FromHours(1).TotalSeconds;

            if (webAppConfig?.JsonStructure?.letsEncryptOptions != null)
            {
                app.UseFluffySpoonLetsEncryptChallengeApprovalMiddleware();
            }

            var createVolatileHostAttempts = 0;

            var volatileHosts = new ConcurrentDictionary <string, CSharpScriptContext>();

            InterfaceToHost.Result <InterfaceToHost.TaskResult.RunInVolatileHostError, InterfaceToHost.TaskResult.RunInVolatileHostComplete>
            performProcessTaskRunInVolatileHost(
                InterfaceToHost.Task.RunInVolatileHost runInVolatileHost)
            {
                if (!volatileHosts.TryGetValue(runInVolatileHost.hostId, out var volatileHost))
                {
                    return(new InterfaceToHost.Result <InterfaceToHost.TaskResult.RunInVolatileHostError, InterfaceToHost.TaskResult.RunInVolatileHostComplete>
                    {
                        err = new InterfaceToHost.TaskResult.RunInVolatileHostError
                        {
                            hostNotFound = new object(),
                        }
                    });
                }

                var stopwatch = System.Diagnostics.Stopwatch.StartNew();

                var fromVolatileHostResult = volatileHost.RunScript(runInVolatileHost.script);

                stopwatch.Stop();

                return(new InterfaceToHost.Result <InterfaceToHost.TaskResult.RunInVolatileHostError, InterfaceToHost.TaskResult.RunInVolatileHostComplete>
                {
                    ok = new InterfaceToHost.TaskResult.RunInVolatileHostComplete
                    {
                        exceptionToString = fromVolatileHostResult.Exception?.ToString(),
                        returnValueToString = fromVolatileHostResult.ReturnValue?.ToString(),
                        durationInMilliseconds = stopwatch.ElapsedMilliseconds,
                    }
                });
            }

            InterfaceToHost.TaskResult performProcessTask(InterfaceToHost.Task task)
            {
                if (task?.createVolatileHost != null)
                {
                    var volatileHostId = System.Threading.Interlocked.Increment(ref createVolatileHostAttempts).ToString();

                    volatileHosts[volatileHostId] = new CSharpScriptContext(BlobLibrary.GetBlobWithSHA256);

                    return(new InterfaceToHost.TaskResult
                    {
                        createVolatileHostResponse = new InterfaceToHost.Result <object, InterfaceToHost.TaskResult.CreateVolatileHostComplete>
                        {
                            ok = new InterfaceToHost.TaskResult.CreateVolatileHostComplete
                            {
                                hostId = volatileHostId,
                            },
                        },
                    });
                }

                if (task?.releaseVolatileHost != null)
                {
                    volatileHosts.TryRemove(task?.releaseVolatileHost.hostId, out var volatileHost);

                    return(new InterfaceToHost.TaskResult
                    {
                        completeWithoutResult = new object(),
                    });
                }

                if (task?.runInVolatileHost != null)
                {
                    return(new InterfaceToHost.TaskResult
                    {
                        runInVolatileHostResponse = performProcessTaskRunInVolatileHost(task?.runInVolatileHost),
                    });
                }

                throw new NotImplementedException("Unexpected task structure.");
            }

            void performProcessTaskAndFeedbackEvent(InterfaceToHost.StartTask taskWithId)
            {
                var taskResult = performProcessTask(taskWithId.task);

                var interfaceEvent = new InterfaceToHost.Event
                {
                    taskComplete = new InterfaceToHost.ResultFromTaskWithId
                    {
                        taskId     = taskWithId.taskId,
                        taskResult = taskResult,
                    }
                };

                processEventAndResultingRequests(interfaceEvent);
            }

            var processRequestCompleteHttpResponse = new ConcurrentDictionary <string, InterfaceToHost.HttpResponse>();

            var persistentProcess = app.ApplicationServices.GetService <IPersistentProcess>();

            void processEventAndResultingRequests(InterfaceToHost.Event interfaceEvent)
            {
                lock (processStoreWriter)
                {
                    var serializedInterfaceEvent = Newtonsoft.Json.JsonConvert.SerializeObject(interfaceEvent, jsonSerializerSettings);

                    var(eventResponses, compositionRecord) = persistentProcess.ProcessEvents(new[] { serializedInterfaceEvent });

                    processStoreWriter.AppendSerializedCompositionRecord(compositionRecord.serializedCompositionRecord);

                    var serializedResponse = eventResponses.Single();

                    InterfaceToHost.ResponseOverSerialInterface structuredResponse = null;

                    try
                    {
                        structuredResponse =
                            Newtonsoft.Json.JsonConvert.DeserializeObject <InterfaceToHost.ResponseOverSerialInterface>(
                                serializedResponse);
                    }
                    catch (Exception parseException)
                    {
                        throw new Exception(
                                  "Failed to parse event response from app. Looks like the loaded elm app is not compatible with the interface.\nResponse from app follows:\n" + serializedResponse,
                                  parseException);
                    }

                    if (structuredResponse?.decodeEventSuccess == null)
                    {
                        throw new Exception("Hosted app failed to decode the event: " + structuredResponse.decodeEventError);
                    }

                    foreach (var requestFromProcess in structuredResponse.decodeEventSuccess)
                    {
                        if (requestFromProcess.completeHttpResponse != null)
                        {
                            processRequestCompleteHttpResponse[requestFromProcess.completeHttpResponse.httpRequestId] =
                                requestFromProcess.completeHttpResponse.response;
                        }

                        if (requestFromProcess.startTask != null)
                        {
                            System.Threading.Tasks.Task.Run(() => performProcessTaskAndFeedbackEvent(requestFromProcess.startTask));
                        }
                    }
                }
            }

            app
            .Use(async(context, next) => await Asp.MiddlewareFromWebAppConfig(webAppConfig, context, next))
            .Run(async(context) =>
            {
                var currentDateTime  = getDateTimeOffset();
                var timeMilli        = currentDateTime.ToUnixTimeMilliseconds();
                var httpRequestIndex = System.Threading.Interlocked.Increment(ref nextHttpRequestIndex);

                var httpRequestId = timeMilli.ToString() + "-" + httpRequestIndex.ToString();

                {
                    var httpEvent = AsPersistentProcessInterfaceHttpRequestEvent(context, httpRequestId, currentDateTime);

                    var httpRequestInterfaceEvent = new InterfaceToHost.Event
                    {
                        httpRequest = httpEvent,
                    };

                    processEventAndResultingRequests(httpRequestInterfaceEvent);
                }

                var waitForHttpResponseClock = System.Diagnostics.Stopwatch.StartNew();

                while (true)
                {
                    if (processRequestCompleteHttpResponse.TryRemove(httpRequestId, out var httpResponse))
                    {
                        var headerContentType =
                            httpResponse.headersToAdd
                            ?.FirstOrDefault(header => header.name?.ToLowerInvariant() == "content-type")
                            ?.values?.FirstOrDefault();

                        context.Response.StatusCode = httpResponse.statusCode;

                        foreach (var headerToAdd in (httpResponse.headersToAdd).EmptyIfNull())
                        {
                            context.Response.Headers[headerToAdd.name] =
                                new Microsoft.Extensions.Primitives.StringValues(headerToAdd.values);
                        }

                        if (headerContentType != null)
                        {
                            context.Response.ContentType = headerContentType;
                        }

                        await context.Response.WriteAsync(httpResponse?.bodyAsString ?? "");
                        break;
                    }

                    if (60 <= waitForHttpResponseClock.Elapsed.TotalSeconds)
                    {
                        throw new TimeoutException(
                            "Persistent process did not return a HTTP response within " +
                            (int)waitForHttpResponseClock.Elapsed.TotalSeconds +
                            " seconds.");
                    }

                    System.Threading.Thread.Sleep(100);
                }

                System.Threading.Thread.MemoryBarrier();
                var cyclicReductionStoreLastAge = currentDateTime - cyclicReductionStoreLastTime;

                if (!(cyclicReductionStoreLastAge?.TotalSeconds < cyclicReductionStoreDistanceSeconds))
                {
                    if (System.Threading.Monitor.TryEnter(cyclicReductionStoreLock))
                    {
                        try
                        {
                            var afterLockCyclicReductionStoreLastAge = currentDateTime - cyclicReductionStoreLastTime;

                            if (afterLockCyclicReductionStoreLastAge?.TotalSeconds < cyclicReductionStoreDistanceSeconds)
                            {
                                return;
                            }

                            var reductionRecord = persistentProcess.ReductionRecordForCurrentState();

                            lock (processStoreWriter)
                            {
                                processStoreWriter.StoreReduction(reductionRecord);
                            }

                            cyclicReductionStoreLastTime = currentDateTime;
                            System.Threading.Thread.MemoryBarrier();
                        }
                        finally
                        {
                            System.Threading.Monitor.Exit(cyclicReductionStoreLock);
                        }
                    }
                }
            });
        }