This repository was archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 55
Expand file tree
/
Copy pathAbstractOperationsController.cs
More file actions
149 lines (132 loc) · 5.68 KB
/
AbstractOperationsController.cs
File metadata and controls
149 lines (132 loc) · 5.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Quantum.IQSharp.Common;
using Microsoft.Quantum.Simulation.Simulators;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
namespace Microsoft.Quantum.IQSharp
{
public abstract class AbstractOperationsController : ControllerBase
{
// TODO: This class may be exposing many more actions than required. Investigate making these protected or using [NonAction].
// The list of operations available in the workspace.
public abstract IEnumerable<OperationInfo> Operations { get; }
/// <summary>
/// Simulates the execution of the given operation using the given arguments
/// to formulate an input tuple.
/// </summary>
[NonAction]
public async Task<object> Simulate(string id, IDictionary<string, string> args, Action<string> logger) =>
await IfReady(async () =>
{
using (var qsim = new QuantumSimulator())
{
qsim.DisableLogToConsole();
qsim.OnLog += logger;
var value = await Find(id).RunAsync(qsim, args);
return value;
}
});
/// <summary>
/// Wraps the result of calling an asynchronous action into a `Response` object.
/// If an Exception is caught, it returns an error response with the Exception as the
/// corresponding error message.
/// </summary>
[NonAction]
public virtual async Task<Response<T>> AsResponse<T>(Func<Action<string>, Task<T>> action)
{
try
{
var messages = new List<string>();
var result = await action(messages.Add);
return new Response<T>(Status.Success, messages.ToArray(), result);
}
catch (InvalidWorkspaceException ws)
{
return new Response<T>(Status.Error, ws.Errors);
}
catch (CompilationErrorsException c)
{
return new Response<T>(Status.Error, c.Errors);
}
catch (Exception e)
{
return new Response<T>(Status.Error, new string[] { e.Message });
}
}
/// <summary>
/// Performs checks to verify if the Controller is ready to execute operations, namely
/// it checks if the Workspace is avaialble and in a success (no errors) state.
/// The method throws Exceptions if it finds it is not ready to execute.
/// </summary>
protected abstract void CheckIfReady();
/// <summary>
/// Executes the given `action` only if the controller is ready, namely if after calling `CheckIfReady`.
/// </summary>
public virtual async Task<T> IfReady<T>(Func<Task<T>> action)
{
CheckIfReady();
return await action();
}
/// <summary>
/// Finds the given operation within the list of Operations.
/// </summary>
internal bool TryFind(string id, out OperationInfo op)
{
if (Operations == null)
{
throw new ArgumentException($"Workspace is not ready. Try again.");
}
else
{
op = Operations.FirstOrDefault(o => o.FullName == id);
return (op != null);
}
}
/// <summary>
/// Finds the given operation within the list of Operations. If it can't find it, it sets the Status code to 404.
/// </summary>
internal OperationInfo Find(string id)
{
var found = TryFind(id, out var op);
if (!found)
{
if (HttpContext?.Response != null) { HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; }
throw new ArgumentException($"Invalid operation name: {id}");
}
System.Diagnostics.Debug.Assert(op != null);
return op;
}
/// <summary>
/// Decides where to read the arguments for executing a quantum operation.
/// First it checks `RunArguments`. If available it uses that (typically for unittests)
/// Then, it checks if the Request's method is GET, if so, it converts the Query string into a key/value pairs dictionary;
/// if it is POST, it expects a json object in the body and uses JsonToDict to convert that also into a key/value pairs dictionary
/// </summary>
/// <returns></returns>
internal static async Task<IDictionary<string, string>> GetRunArguments(HttpRequest request)
{
if (request == null) return null;
if (request.Method == "GET") return new Dictionary<string, string>(request.Query.Select(kv => KeyValuePair.Create(kv.Key, kv.Value.ToString())));
if (request.Method == "POST")
{
using (var body = new StreamReader(request.Body))
{
var json = await body.ReadToEndAsync();
return JsonConverters.JsonToDict(json);
}
}
return null;
}
}
}
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously