示例#1
0
        /// <summary>
        /// Enable Debug Adapter Protocol for the running adapter.
        /// </summary>
        /// <param name="botAdapter">The <see cref="BotAdapter"/> to enable.</param>
        /// <param name="port">port to listen on.</param>
        /// <param name="sourceMap">ISourceMap to use (default will be SourceMap()).</param>
        /// <param name="breakpoints">IBreakpoints to use (default will be SourceMap()).</param>
        /// <param name="terminate">Termination function (Default is Environment.Exit().</param>
        /// <param name="events">IEvents to use (Default is Events).</param>
        /// <param name="codeModel">ICodeModel to use (default is internal implementation).</param>
        /// <param name="dataModel">IDataModel to use (default is internal implementation).</param>
        /// <param name="logger">ILogger to use (Default is NullLogger).</param>
        /// <param name="coercion">ICoercion to use (default is internal implementation).</param>
        /// <returns>The <see cref="BotAdapter"/>.</returns>
        public static BotAdapter UseDebugger(
            this BotAdapter botAdapter,
            int port,
            ISourceMap sourceMap     = null,
            IBreakpoints breakpoints = null,
            Action terminate         = null,
            IEvents events           = null,
            ICodeModel codeModel     = null,
            IDataModel dataModel     = null,
            ILogger logger           = null,
            ICoercion coercion       = null)
        {
            codeModel = codeModel ?? new CodeModel();
            var debuggerSourceMap = new DebuggerSourceMap(codeModel);

            DebugSupport.SourceMap = sourceMap ?? debuggerSourceMap;
            return(botAdapter.Use(
                       new DialogDebugAdapter(
                           port: port,
                           sourceMap: DebugSupport.SourceMap,
                           breakpoints: breakpoints ?? DebugSupport.SourceMap as IBreakpoints,
                           terminate: terminate,
                           events: events,
                           codeModel: codeModel,
                           dataModel: dataModel,
                           logger: logger)));
        }
示例#2
0
        private async Task<Protocol.Message> DispatchAsync(Protocol.Message message, CancellationToken cancellationToken)
        {
            if (message is Protocol.Request<Protocol.Initialize> initialize)
            {
                var body = MakeCapabilities();
                var response = Protocol.Response.From(NextSeq, initialize, body);
                await SendAsync(response, cancellationToken).ConfigureAwait(false);
                return Protocol.Event.From(NextSeq, "initialized", new { });
            }
            else if (message is Protocol.Request<Protocol.Launch> launch)
            {
                return Protocol.Response.From(NextSeq, launch, new { });
            }
            else if (message is Protocol.Request<Protocol.Attach> attach)
            {
                return Protocol.Response.From(NextSeq, attach, new { });
            }
            else if (message is Protocol.Request<Protocol.SetBreakpoints> setBreakpoints)
            {
                var arguments = setBreakpoints.Arguments;
                var file = Path.GetFileName(arguments.Source.Path);
                await OutputAsync($"Set breakpoints for {file}", null, cancellationToken).ConfigureAwait(false);

                var breakpoints = this.breakpoints.SetBreakpoints(arguments.Source, arguments.Breakpoints);
                foreach (var breakpoint in breakpoints)
                {
                    if (breakpoint.Verified)
                    {
                        var item = this.breakpoints.ItemFor(breakpoint);
                        await OutputAsync($"Set breakpoint at {codeModel.NameFor(item)}", item, cancellationToken).ConfigureAwait(false);
                    }
                }

                return Protocol.Response.From(NextSeq, setBreakpoints, new { breakpoints });
            }
            else if (message is Protocol.Request<Protocol.SetFunctionBreakpoints> setFunctionBreakpoints)
            {
                var arguments = setFunctionBreakpoints.Arguments;
                await OutputAsync($"Set function breakpoints.", null, cancellationToken).ConfigureAwait(false);
                var breakpoints = this.breakpoints.SetBreakpoints(arguments.Breakpoints);
                foreach (var breakpoint in breakpoints)
                {
                    if (breakpoint.Verified)
                    {
                        var item = this.breakpoints.ItemFor(breakpoint);
                        await OutputAsync($"Set breakpoint at {codeModel.NameFor(item)}", item, cancellationToken).ConfigureAwait(false);
                    }
                }

                return Protocol.Response.From(NextSeq, setFunctionBreakpoints, new { breakpoints });
            }
            else if (message is Protocol.Request<Protocol.SetExceptionBreakpoints> setExceptionBreakpoints)
            {
                var arguments = setExceptionBreakpoints.Arguments;
                this.events.Reset(arguments.Filters);

                return Protocol.Response.From(NextSeq, setExceptionBreakpoints, new { });
            }
            else if (message is Protocol.Request<Protocol.Threads> threads)
            {
                var body = new
                {
                    threads = this.threads.Select(t => new { id = t.Key, name = t.Value.Name }).ToArray()
                };

                return Protocol.Response.From(NextSeq, threads, body);
            }
            else if (message is Protocol.Request<Protocol.StackTrace> stackTrace)
            {
                var arguments = stackTrace.Arguments;
                var thread = this.threads[arguments.ThreadId];

                var frames = thread.Frames;
                var stackFrames = new List<Protocol.StackFrame>();
                foreach (var frame in frames)
                {
                    var stackFrame = new Protocol.StackFrame()
                    {
                        Id = EncodeFrame(thread, frame),
                        Name = frame.Name
                    };

                    if (this.sourceMap.TryGetValue(frame.Item, out var range))
                    {
                        DebuggerSourceMap.Assign(stackFrame, range);
                    }

                    stackFrames.Add(stackFrame);
                }

                return Protocol.Response.From(NextSeq, stackTrace, new { stackFrames });
            }
            else if (message is Protocol.Request<Protocol.Scopes> scopes)
            {
                var arguments = scopes.Arguments;
                DecodeFrame(arguments.FrameId, out var thread, out var frame);
                const bool expensive = false;

                var body = new
                {
                    scopes = new[]
                    {
                        new { expensive, name = frame.Name, variablesReference = EncodeValue(thread, frame.Data) }
                    }
                };

                return Protocol.Response.From(NextSeq, scopes, body);
            }
            else if (message is Protocol.Request<Protocol.Variables> vars)
            {
                var arguments = vars.Arguments;
                DecodeValue(arguments.VariablesReference, out var thread, out var context);

                var names = this.dataModel.Names(context);

                var body = new
                {
                    variables = (from name in names
                                 let value = dataModel[context, name]
                                 let variablesReference = EncodeValue(thread, value)
                                 select new { name = dataModel.ToString(name), value = dataModel.ToString(value), variablesReference })
                                .ToArray()
                };

                return Protocol.Response.From(NextSeq, vars, body);
            }
            else if (message is Protocol.Request<Protocol.SetVariable> setVariable)
            {
                var arguments = setVariable.Arguments;
                DecodeValue(arguments.VariablesReference, out var thread, out var context);

                var value = this.dataModel[context, arguments.Name] = JToken.Parse(arguments.Value);

                var body = new
                {
                    value = dataModel.ToString(value),
                    variablesReference = EncodeValue(thread, value)
                };

                return Protocol.Response.From(NextSeq, setVariable, body);
            }
            else if (message is Protocol.Request<Protocol.Evaluate> evaluate)
            {
                var arguments = evaluate.Arguments;
                DecodeFrame(arguments.FrameId, out var thread, out var frame);
                var expression = arguments.Expression.Trim('"');
                var result = frame.Evaluate(expression);
                if (result != null)
                {
                    var body = new
                    {
                        result = dataModel.ToString(result),
                        variablesReference = EncodeValue(thread, result),
                    };

                    return Protocol.Response.From(NextSeq, evaluate, body);
                }
                else
                {
                    return Protocol.Response.Fail(NextSeq, evaluate, string.Empty);
                }
            }
            else if (message is Protocol.Request<Protocol.Continue> cont)
            {
                bool found = this.threads.TryGetValue(cont.Arguments.ThreadId, out var thread);
                if (found)
                {
                    thread.Run.Post(Phase.Continue);
                }

                return Protocol.Response.From(NextSeq, cont, new { allThreadsContinued = false });
            }
            else if (message is Protocol.Request<Protocol.Pause> pause)
            {
                bool found = this.threads.TryGetValue(pause.Arguments.ThreadId, out var thread);
                if (found)
                {
                    thread.Run.Post(Phase.Pause);
                }

                return Protocol.Response.From(NextSeq, pause, new { });
            }
            else if (message is Protocol.Request<Protocol.Next> next)
            {
                bool found = this.threads.TryGetValue(next.Arguments.ThreadId, out var thread);
                if (found)
                {
                    thread.Run.Post(Phase.Next);
                }

                return Protocol.Response.From(NextSeq, next, new { });
            }
            else if (message is Protocol.Request<Protocol.Terminate> terminate)
            {
                if (this.terminate != null)
                {
                    this.terminate();
                }

                return Protocol.Response.From(NextSeq, terminate, new { });
            }
            else if (message is Protocol.Request<Protocol.Disconnect> disconnect)
            {
                var arguments = disconnect.Arguments;
                if (arguments.TerminateDebuggee && this.terminate != null)
                {
                    this.terminate();
                }

                // if attach, possibly run all threads
                return Protocol.Response.From(NextSeq, disconnect, new { });
            }
            else if (message is Protocol.Request request)
            {
                return Protocol.Response.From(NextSeq, request, new { });
            }
            else if (message is Protocol.Event @event)
            {
                throw new NotImplementedException();
            }
            else
            {
                throw new NotImplementedException();
            }
        }
        private async Task <Message> DispatchAsync(Message message, CancellationToken cancellationToken)
        {
            if (message is Request request)
            {
                if (message is Request <Initialize> initialize)
                {
                    var body     = MakeCapabilities();
                    var response = Response.From(NextSeq, initialize, body);
                    await SendAsync(response, cancellationToken).ConfigureAwait(false);

                    return(Event.From(NextSeq, "initialized", new { }));
                }

                if (message is Request <Launch> launch)
                {
                    _options = launch.Arguments;
                    return(Response.From(NextSeq, launch, new { }));
                }

                if (message is Request <Attach> attach)
                {
                    _options = attach.Arguments;
                    return(Response.From(NextSeq, attach, new { }));
                }

                if (message is Request <SetBreakpoints> setBreakpoints)
                {
                    var arguments = setBreakpoints.Arguments;
                    var file      = Path.GetFileName(arguments.Source.Path);
                    await OutputAsync($"Set breakpoints for {file}", null, null, cancellationToken).ConfigureAwait(false);

                    var breakpoints = _breakpoints.SetBreakpoints(arguments.Source, arguments.Breakpoints);
                    foreach (var breakpoint in breakpoints)
                    {
                        if (breakpoint.Verified)
                        {
                            var item = _breakpoints.ItemFor(breakpoint);
                            await OutputAsync($"Set breakpoint at {_codeModel.NameFor(item)}", item, null, cancellationToken).ConfigureAwait(false);
                        }
                    }

                    return(Response.From(NextSeq, setBreakpoints, new { breakpoints }));
                }

                if (message is Request <SetFunctionBreakpoints> setFunctionBreakpoints)
                {
                    var arguments = setFunctionBreakpoints.Arguments;
                    await OutputAsync("Set function breakpoints.", null, null, cancellationToken).ConfigureAwait(false);

                    var breakpoints = _breakpoints.SetBreakpoints(arguments.Breakpoints);
                    foreach (var breakpoint in breakpoints)
                    {
                        if (breakpoint.Verified)
                        {
                            var item = _breakpoints.ItemFor(breakpoint);
                            await OutputAsync($"Set breakpoint at {_codeModel.NameFor(item)}", item, null, cancellationToken).ConfigureAwait(false);
                        }
                    }

                    return(Response.From(NextSeq, setFunctionBreakpoints, new { breakpoints }));
                }

                if (message is Request <SetExceptionBreakpoints> setExceptionBreakpoints)
                {
                    var arguments = setExceptionBreakpoints.Arguments;
                    _events.Reset(arguments.Filters);

                    return(Response.From(NextSeq, setExceptionBreakpoints, new { }));
                }

                if (message is Request <Threads> threads)
                {
                    var body = new
                    {
                        threads = _threads.Select(t => new
                        {
                            id   = t.Key,
                            name = t.Value.Name
                        }).ToArray()
                    };

                    return(Response.From(NextSeq, threads, body));
                }

                if (message is Request <StackTrace> stackTrace)
                {
                    var arguments = stackTrace.Arguments;
                    var thread    = _threads[arguments.ThreadId];

                    var frames      = thread.Frames;
                    var stackFrames = new List <StackFrame>();
                    foreach (var frame in frames)
                    {
                        var stackFrame = new StackFrame
                        {
                            Id   = EncodeFrame(thread, frame),
                            Name = frame.Name
                        };

                        var item = _codeModel.NameFor(frame.Item);
                        DebuggerSourceMap.Assign(stackFrame, item, frame.More);

                        if (_sourceMap.TryGetValue(frame.Item, out var range))
                        {
                            DebuggerSourceMap.Assign(stackFrame, range);
                        }

                        stackFrames.Add(stackFrame);
                    }

                    return(Response.From(NextSeq, stackTrace, new { stackFrames }));
                }

                if (message is Request <Scopes> scopes)
                {
                    var arguments = scopes.Arguments;
                    DecodeFrame(arguments.FrameId, out var thread, out var frame);
                    const bool expensive = false;

                    var body = new
                    {
                        scopes = new[]
                        {
                            new
                            {
                                expensive,
                                name = frame.Name,
                                variablesReference = EncodeValue(thread, frame.Data)
                            }
                        }
                    };

                    return(Response.From(NextSeq, scopes, body));
                }

                if (message is Request <Variables> vars)
                {
                    var arguments = vars.Arguments;
                    DecodeValue(arguments.VariablesReference, out var arena, out var context);

                    var names = _dataModel.Names(context);

                    var body = new
                    {
                        variables = (from name in names
                                     let value = _dataModel[context, name]
                                                 let variablesReference = EncodeValue(arena, value)
                                                                          select new
                        {
                            name = _dataModel.ToString(name),
                            value = _dataModel.ToString(value),
                            variablesReference
                        })
                                    .ToArray()
                    };

                    return(Response.From(NextSeq, vars, body));
                }

                if (message is Request <SetVariable> setVariable)
                {
                    var arguments = setVariable.Arguments;
                    DecodeValue(arguments.VariablesReference, out var arena, out var context);

                    var value = _dataModel[context, arguments.Name] = JToken.Parse(arguments.Value);

                    var body = new
                    {
                        value = _dataModel.ToString(value),
                        variablesReference = EncodeValue(arena, value)
                    };

                    return(Response.From(NextSeq, setVariable, body));
                }

                if (message is Request <Evaluate> evaluate)
                {
                    var arguments = evaluate.Arguments;
                    DecodeFrame(arguments.FrameId, out var thread, out var frame);
                    var expression = arguments.Expression.Trim('"');

                    try
                    {
                        var result = frame.Evaluate(expression);
                        var body   = new
                        {
                            result             = _dataModel.ToString(result),
                            variablesReference = EncodeValue(thread, result),
                        };

                        return(Response.From(NextSeq, evaluate, body));
                    }
#pragma warning disable CA1031 // Do not catch general exception types (catch any exception and return it)
                    catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                    {
                        return(Response.Fail(NextSeq, evaluate, ex.Message));
                    }
                }

                Response Post <TBody>(PerThread perThread, Phase phase, TBody body)
                {
                    // "constructing the response" and "posting to the thread" have side-effects
                    // for extra determinism, construct the response before signaling the thread
                    var response = Response.From(NextSeq, request, body);

                    var found = _threads.TryGetValue(perThread.ThreadId, out var thread);

                    if (found)
                    {
                        thread.Run.Post(phase);
                    }

                    return(response);
                }

                if (message is Request <Continue> cont)
                {
                    return(Post(cont.Arguments, Phase.Continue, new { allThreadsContinued = false }));
                }

                if (message is Request <Pause> pause)
                {
                    return(Post(pause.Arguments, Phase.Pause, new { }));
                }

                if (message is Request <Next> next)
                {
                    return(Post(next.Arguments, Phase.Next, new { }));
                }

                if (message is Request <Terminate> terminate)
                {
                    if (_terminate != null)
                    {
                        _terminate();
                    }

                    return(Response.From(NextSeq, terminate, new { }));
                }

                if (message is Request <Disconnect> disconnect)
                {
                    var arguments = disconnect.Arguments;
                    if (arguments.TerminateDebuggee && _terminate != null)
                    {
                        _terminate();
                    }
                    else
                    {
                        ResetOnDisconnect();
                    }

                    return(Response.From(NextSeq, disconnect, new { }));
                }

                return(Response.From(NextSeq, request, new { }));
            }

            if (message is Event @event)
            {
                throw new NotImplementedException();
            }

            throw new NotImplementedException();
        }