提交 62265946 编写于 作者: 麦壳饼's avatar 麦壳饼

优化C#脚本处理机制。

上级 f930f3ad
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Migrations\**" />
<EmbeddedResource Remove="Migrations\**" />
<None Remove="Migrations\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="6.0.4" /> <PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="6.0.4" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="6.0.4" /> <PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="6.0.4" />
...@@ -17,8 +23,5 @@ ...@@ -17,8 +23,5 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\IoTSharp.Data\IoTSharp.Data.csproj" /> <ProjectReference Include="..\IoTSharp.Data\IoTSharp.Data.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
</Project> </Project>
...@@ -14,25 +14,52 @@ using IronPython.Runtime; ...@@ -14,25 +14,52 @@ using IronPython.Runtime;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Dynamic; using System.Dynamic;
using Microsoft.Extensions.Caching.Memory;
using System.Text;
namespace IoTSharp.Interpreter namespace IoTSharp.Interpreter
{ {
public class CSharpScriptEngine : ScriptEngineBase, IDisposable public class CSharpScriptEngine : ScriptEngineBase, IDisposable
{ {
private bool disposedValue; private bool disposedValue;
private IMemoryCache _cache;
public CSharpScriptEngine(ILogger<CSharpScriptEngine> logger, IOptions<EngineSetting> _opt, IMemoryCache cache) :base(logger,_opt.Value, Task.Factory.CancellationToken)
public CSharpScriptEngine(ILogger<CSharpScriptEngine> logger, IOptions<EngineSetting> _opt):base(logger,_opt.Value, Task.Factory.CancellationToken)
{ {
//CSScript.EvaluatorConfig _cache = cache;
} }
public override string Do(string _source,string input) public override string Do(string _source,string input)
{ {
ICSAction csa = CSScript.Evaluator.LoadCode<ICSAction>(_source); var runscript = _cache.GetOrCreate(_source, c =>
dynamic result = csa.Run(input); {
var src = _source.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.TrimEntries);
StringBuilder _using = new StringBuilder();
StringBuilder _body = new StringBuilder();
src.ToList().ForEach(l =>
{
if (l.StartsWith("using "))
{
_using.AppendLine(l);
}
else
{
_body.AppendLine(l);
}
});
return CSScript.Evaluator
.CreateDelegate(@$"
{_using}
dynamic runscript(dynamic input)
{{
{_body}
}}");
});
var expConverter = new ExpandoObjectConverter();
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(input, expConverter);
dynamic result = runscript(obj);
var json= System.Text.Json.JsonSerializer.Serialize(result); var json= System.Text.Json.JsonSerializer.Serialize(result);
_logger.LogDebug($"source:{Environment.NewLine}{ _source}{Environment.NewLine}{Environment.NewLine}input:{Environment.NewLine}{ input}{Environment.NewLine}{Environment.NewLine} ouput:{Environment.NewLine}{ json}{Environment.NewLine}{Environment.NewLine}"); _logger.LogDebug($"source:{Environment.NewLine}{ _source}{Environment.NewLine}{Environment.NewLine}input:{Environment.NewLine}{ input}{Environment.NewLine}{Environment.NewLine} ouput:{Environment.NewLine}{ json}{Environment.NewLine}{Environment.NewLine}");
return json; return json;
...@@ -64,19 +91,5 @@ namespace IoTSharp.Interpreter ...@@ -64,19 +91,5 @@ namespace IoTSharp.Interpreter
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
} }
public interface ICSAction
{
dynamic Run(string input);
}
} }
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.1.0" /> <PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.1.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
......
using IoTSharp.Interpreter; using IoTSharp.Interpreter;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
...@@ -37,7 +38,7 @@ namespace IoTSharp.Test ...@@ -37,7 +38,7 @@ namespace IoTSharp.Test
_lua_engine = new LuaScriptEngine (lgf.CreateLogger<LuaScriptEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 })); _lua_engine = new LuaScriptEngine (lgf.CreateLogger<LuaScriptEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 }));
_c_engine = new CScriptEngine(lgf.CreateLogger<CScriptEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 })); _c_engine = new CScriptEngine(lgf.CreateLogger<CScriptEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 }));
_sql_engine=new SQLEngine(lgf.CreateLogger<SQLEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 })); _sql_engine=new SQLEngine(lgf.CreateLogger<SQLEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 }));
_csharp_engine = new CSharpScriptEngine (lgf.CreateLogger<CSharpScriptEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 })); _csharp_engine = new CSharpScriptEngine (lgf.CreateLogger<CSharpScriptEngine>(), Options.Create(new Interpreter.EngineSetting() { Timeout = 4 }), new MemoryCache(new MemoryCacheOptions()));
} }
[TestMethod] [TestMethod]
public void TestJavaScript() public void TestJavaScript()
...@@ -127,8 +128,9 @@ return fff:new() ...@@ -127,8 +128,9 @@ return fff:new()
public void TestCSharpScript() public void TestCSharpScript()
{ {
var intput = System.Text.Json.JsonSerializer.Serialize(new { temperature = 39, height = 192, weight = 121 }); var intput = System.Text.Json.JsonSerializer.Serialize(new { temperature = 39, height = 192, weight = 121 });
for (int i = 0; i < 1000; i++)
string output = _csharp_engine.Do(@" {
string output = _csharp_engine.Do(@"
var _m = (input.height / 100); var _m = (input.height / 100);
var output = new { var output = new {
fever= input.temperature > 38 ? true : false, fever= input.temperature > 38 ? true : false,
...@@ -136,10 +138,11 @@ var output = new { ...@@ -136,10 +138,11 @@ var output = new {
}; };
return output; return output;
", intput); ", intput);
var t = new { fever = true, fat = true };
var t = new { fever = true, fat = true }; var outpuobj = System.Text.Json.JsonSerializer.Deserialize(output, t.GetType());
var outpuobj = System.Text.Json.JsonSerializer.Deserialize(output, t.GetType()); Assert.AreEqual(outpuobj, t);
Assert.AreEqual(outpuobj, t); }
} }
} }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IoTSharp.Extensions
{
public static class ExecutorExtensions
{
}
}
/* Copyright 2018 by Nomadeon Software LLC. Licensed uinder MIT: https://opensource.org/licenses/MIT */
using System;
using System.Collections.Generic;
using System.Text;
using LiteDB;
using System.Linq;
using System.Threading.Tasks;
#pragma warning disable CS1584,CS0419,CS1570
namespace LiteQueue
{
public class QueueEntry<T>
{
public long Id { get; set; }
public T Payload { get; set; }
public bool IsCheckedOut { get; set; }
public QueueEntry()
{
}
public QueueEntry(T payload)
{
Payload = payload;
}
}
/// <summary>
/// Uses LiteDB to provide a persisted, thread safe, (optionally) transactional, FIFO queue.
///
/// Suitable for use on clients as a lightweight, portable alternative to MSMQ. Not recommended for use
/// on large server side applications due to performance limitations of LiteDB.
/// </summary>
public class LiteQueue<T>
{
ILiteCollection<QueueEntry<T>> _collection;
bool _transactional = true;
readonly object _dequeueLock = new object();
/// <summary>
/// Impacts operation of <see cref="Dequeue"/> method. Can only be set once in constructor.
/// </summary>
public bool IsTransactional
{
get
{
return _transactional;
}
}
/// <summary>
/// Creates a collection for you in the database
/// </summary>
/// <param name="db">The LiteDB database. You are responsible for its lifecycle (using/dispose)</param>
/// <param name="collectionName">Name of the collection to create</param>
/// <param name="transactional">Whether the queue should use transaction logic, default true</param>
public LiteQueue(LiteDatabase db, string collectionName, bool transactional = true)
{
_collection = db.GetCollection<QueueEntry<T>>(collectionName);
_transactional = transactional;
}
/// <summary>
/// Uses the provided database collection
/// </summary>
/// <param name="collection">A LiteDB collection.</param>
/// <param name="transactional">Whether the queue should use transaction logic, default true</param>
public LiteQueue(ILiteCollection<QueueEntry<T>> collection, bool transactional = true)
{
_collection = collection;
_transactional = transactional;
_collection.EnsureIndex(x => x.Id);
_collection.EnsureIndex(x => x.IsCheckedOut);
}
/// <summary>
/// Creates a collection for you in the database, collection's name is <typeparamref name="T"/>
/// </summary>
/// <param name="db">The LiteDB database. You are responsible for its lifecycle (using/dispose)</param>
/// <param name="transactional">Whether the queue should use transaction logic, default true</param>
public LiteQueue(LiteDatabase db, bool transactional = true)
{
_collection = db.GetCollection<QueueEntry<T>>(typeof(T).Name);
_transactional = transactional;
}
/// <summary>
/// Adds a single item to queue. See <see cref="Enqueue(IEnumerable{T})"/> for adding a batch.
/// </summary>
/// <param name="item"></param>
public void Enqueue(T item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
QueueEntry<T> insert = new QueueEntry<T>(item);
_collection.Insert(insert);
}
/// <summary>
/// Adds a batch of items to the queue. See <see cref="Enqueue(T)"/> for adding a single item.
/// </summary>
/// <param name="items"></param>
public void Enqueue(IEnumerable<T> items)
{
List<QueueEntry<T>> inserts = new List<QueueEntry<T>>();
foreach (var item in items)
{
inserts.Add(new QueueEntry<T>(item));
}
_collection.InsertBulk(inserts);
}
/// <summary>
/// Transactional queues:
/// Marks item as checked out but does not remove from queue. You are expected to later call <see cref="Commit(QueueEntry{T})"/> or <see cref="Abort(QueueEntry{T})"/>
/// Non-transactional queues:
/// Removes item from queue with no need to call <see cref="Commit(QueueEntry{T})"/> or <see cref="Abort(QueueEntry{T})"/>
/// </summary>
/// <returns>An item if found or null</returns>
public QueueEntry<T> Dequeue()
{
var result = Dequeue(1);
if (result.Count == 0)
{
return null;
}
else
{
return result[0];
}
}
/// <summary>
/// Batch equivalent of <see cref="Dequeue"/>
/// </summary>
/// <param name="batchSize">The maximum number of items to dequeue</param>
/// <returns>The items found or an empty collection (never null)</returns>
public List<QueueEntry<T>> Dequeue(int batchSize)
{
if (_transactional)
{
lock (_dequeueLock)
{
var items = _collection.Find(x => !x.IsCheckedOut, 0, batchSize);
// Capture the result before changing IsCheckedOut, otherwise items is being changed
var result = new List<QueueEntry<T>>(items);
foreach (var item in result)
{
item.IsCheckedOut = true;
_collection.Update(item);
}
return result;
}
}
else
{
var items = _collection.Find(x => true, 0, batchSize);
var result = new List<QueueEntry<T>>(items);
foreach (var item in items)
{
_collection.Delete(new BsonValue(item.Id));
}
return result;
}
}
/// <summary>
/// Obtains list of items currently checked out (but not yet commited or aborted) as a result of Dequeue calls on a transactional queue
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when queue is not transactional</exception>
/// <returns>Items found or empty collection (never null)</returns>
public List<QueueEntry<T>> CurrentCheckouts()
{
if (!_transactional)
{
throw new InvalidOperationException("Cannot call " + nameof(CurrentCheckouts) + " unless queue is transactional");
}
var records = _collection.Find(item => item.IsCheckedOut);
return new List<QueueEntry<T>>(records);
}
/// <summary>
/// Aborts all currently checked out items. Equivalent of calling <see cref="CurrentCheckouts"/> followed by <see cref="Abort(IEnumerable{QueueEntry{T}})"/>
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when queue is not transactional</exception>
public void ResetOrphans()
{
if (!_transactional)
{
throw new InvalidOperationException("Cannot call " + nameof(ResetOrphans) + " unless queue is transactional");
}
var checkouts = CurrentCheckouts();
Abort(checkouts);
}
/// <summary>
/// Aborts a transaction on a single item. See <see cref="Abort(IEnumerable{QueueEntry{T}})"/> for batches.
/// </summary>
/// <param name="item">An item that was obtained from a <see cref="Dequeue"/> call</param>
/// <exception cref="InvalidOperationException">Thrown when queue is not transactional</exception>
public void Abort(QueueEntry<T> item)
{
if (!_transactional)
{
throw new InvalidOperationException("Cannot call " + nameof(Abort) + " unless queue is transactional");
}
else if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
item.IsCheckedOut = false;
_collection.Update(item);
}
/// <summary>
/// Aborts a transation on a group of items. See <see cref="Abort(QueueEntry{T})"/> for a single item.
/// </summary>
/// <param name="items">Items that were obtained from a <see cref="Dequeue"/> call</param>
/// <exception cref="InvalidOperationException">Thrown when queue is not transactional</exception>
public void Abort(IEnumerable<QueueEntry<T>> items)
{
foreach (var item in items)
{
Abort(item);
}
}
/// <summary>
/// Commits a transaction on a single item. See <see cref="Commit(IEnumerable{QueueEntry{T}})"/> for batches.
/// </summary>
/// <param name="item">An item that was obtained from a <see cref="Dequeue"/> call</param>
/// <exception cref="InvalidOperationException">Thrown when queue is not transactional</exception>
public void Commit(QueueEntry<T> item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
if (!_transactional)
{
throw new InvalidOperationException("Cannot call " + nameof(Commit) + " unless queue is transactional");
}
BsonValue id = new BsonValue(item.Id);
_collection.Delete(id);
}
/// <summary>
/// Commits a transation on a group of items. See <see cref="Commit(QueueEntry{T})/> for a single item.
/// </summary>
/// <param name="items">Items that were obtained from a <see cref="Dequeue"/> call</param>
/// <exception cref="InvalidOperationException">Thrown when queue is not transactional</exception>
public void Commit(IEnumerable<QueueEntry<T>> items)
{
foreach (var item in items)
{
Commit(item);
}
}
/// <summary>
/// Number of items in queue, including those that have been checked out.
/// </summary>
public int Count()
{
return _collection.Count();
}
/// <summary>
/// Removes all items from queue, including any that have been checked out.
/// </summary>
public void Clear()
{
_collection.DeleteAll();
}
}
}
#pragma warning restore CS1584, CS0419, CS1570
\ No newline at end of file
...@@ -922,113 +922,5 @@ ...@@ -922,113 +922,5 @@
解决单例注入问题 jy 解决单例注入问题 jy
</summary> </summary>
</member> </member>
<member name="T:LiteQueue.LiteQueue`1">
<summary>
Uses LiteDB to provide a persisted, thread safe, (optionally) transactional, FIFO queue.
Suitable for use on clients as a lightweight, portable alternative to MSMQ. Not recommended for use
on large server side applications due to performance limitations of LiteDB.
</summary>
</member>
<member name="P:LiteQueue.LiteQueue`1.IsTransactional">
<summary>
Impacts operation of <see cref="M:LiteQueue.LiteQueue`1.Dequeue"/> method. Can only be set once in constructor.
</summary>
</member>
<member name="M:LiteQueue.LiteQueue`1.#ctor(LiteDB.LiteDatabase,System.String,System.Boolean)">
<summary>
Creates a collection for you in the database
</summary>
<param name="db">The LiteDB database. You are responsible for its lifecycle (using/dispose)</param>
<param name="collectionName">Name of the collection to create</param>
<param name="transactional">Whether the queue should use transaction logic, default true</param>
</member>
<member name="M:LiteQueue.LiteQueue`1.#ctor(LiteDB.ILiteCollection{LiteQueue.QueueEntry{`0}},System.Boolean)">
<summary>
Uses the provided database collection
</summary>
<param name="collection">A LiteDB collection.</param>
<param name="transactional">Whether the queue should use transaction logic, default true</param>
</member>
<member name="M:LiteQueue.LiteQueue`1.#ctor(LiteDB.LiteDatabase,System.Boolean)">
<summary>
Creates a collection for you in the database, collection's name is <typeparamref name="T"/>
</summary>
<param name="db">The LiteDB database. You are responsible for its lifecycle (using/dispose)</param>
<param name="transactional">Whether the queue should use transaction logic, default true</param>
</member>
<member name="M:LiteQueue.LiteQueue`1.Enqueue(`0)">
<summary>
Adds a single item to queue. See <see cref="M:LiteQueue.LiteQueue`1.Enqueue(System.Collections.Generic.IEnumerable{`0})"/> for adding a batch.
</summary>
<param name="item"></param>
</member>
<member name="M:LiteQueue.LiteQueue`1.Enqueue(System.Collections.Generic.IEnumerable{`0})">
<summary>
Adds a batch of items to the queue. See <see cref="M:LiteQueue.LiteQueue`1.Enqueue(`0)"/> for adding a single item.
</summary>
<param name="items"></param>
</member>
<member name="M:LiteQueue.LiteQueue`1.Dequeue">
<summary>
Transactional queues:
Marks item as checked out but does not remove from queue. You are expected to later call <see cref="M:LiteQueue.LiteQueue`1.Commit(LiteQueue.QueueEntry{`0})"/> or <see cref="M:LiteQueue.LiteQueue`1.Abort(LiteQueue.QueueEntry{`0})"/>
Non-transactional queues:
Removes item from queue with no need to call <see cref="M:LiteQueue.LiteQueue`1.Commit(LiteQueue.QueueEntry{`0})"/> or <see cref="M:LiteQueue.LiteQueue`1.Abort(LiteQueue.QueueEntry{`0})"/>
</summary>
<returns>An item if found or null</returns>
</member>
<member name="M:LiteQueue.LiteQueue`1.Dequeue(System.Int32)">
<summary>
Batch equivalent of <see cref="M:LiteQueue.LiteQueue`1.Dequeue"/>
</summary>
<param name="batchSize">The maximum number of items to dequeue</param>
<returns>The items found or an empty collection (never null)</returns>
</member>
<member name="M:LiteQueue.LiteQueue`1.CurrentCheckouts">
<summary>
Obtains list of items currently checked out (but not yet commited or aborted) as a result of Dequeue calls on a transactional queue
</summary>
<exception cref="T:System.InvalidOperationException">Thrown when queue is not transactional</exception>
<returns>Items found or empty collection (never null)</returns>
</member>
<member name="M:LiteQueue.LiteQueue`1.ResetOrphans">
<summary>
Aborts all currently checked out items. Equivalent of calling <see cref="M:LiteQueue.LiteQueue`1.CurrentCheckouts"/> followed by <see cref="M:LiteQueue.LiteQueue`1.Abort(System.Collections.Generic.IEnumerable{LiteQueue.QueueEntry{`0}})"/>
</summary>
<exception cref="T:System.InvalidOperationException">Thrown when queue is not transactional</exception>
</member>
<member name="M:LiteQueue.LiteQueue`1.Abort(LiteQueue.QueueEntry{`0})">
<summary>
Aborts a transaction on a single item. See <see cref="M:LiteQueue.LiteQueue`1.Abort(System.Collections.Generic.IEnumerable{LiteQueue.QueueEntry{`0}})"/> for batches.
</summary>
<param name="item">An item that was obtained from a <see cref="M:LiteQueue.LiteQueue`1.Dequeue"/> call</param>
<exception cref="T:System.InvalidOperationException">Thrown when queue is not transactional</exception>
</member>
<member name="M:LiteQueue.LiteQueue`1.Abort(System.Collections.Generic.IEnumerable{LiteQueue.QueueEntry{`0}})">
<summary>
Aborts a transation on a group of items. See <see cref="M:LiteQueue.LiteQueue`1.Abort(LiteQueue.QueueEntry{`0})"/> for a single item.
</summary>
<param name="items">Items that were obtained from a <see cref="M:LiteQueue.LiteQueue`1.Dequeue"/> call</param>
<exception cref="T:System.InvalidOperationException">Thrown when queue is not transactional</exception>
</member>
<member name="M:LiteQueue.LiteQueue`1.Commit(LiteQueue.QueueEntry{`0})">
<summary>
Commits a transaction on a single item. See <see cref="M:LiteQueue.LiteQueue`1.Commit(System.Collections.Generic.IEnumerable{LiteQueue.QueueEntry{`0}})"/> for batches.
</summary>
<param name="item">An item that was obtained from a <see cref="M:LiteQueue.LiteQueue`1.Dequeue"/> call</param>
<exception cref="T:System.InvalidOperationException">Thrown when queue is not transactional</exception>
</member>
<!-- Badly formed XML comment ignored for member "M:LiteQueue.LiteQueue`1.Commit(System.Collections.Generic.IEnumerable{LiteQueue.QueueEntry{`0}})" -->
<member name="M:LiteQueue.LiteQueue`1.Count">
<summary>
Number of items in queue, including those that have been checked out.
</summary>
</member>
<member name="M:LiteQueue.LiteQueue`1.Clear">
<summary>
Removes all items from queue, including any that have been checked out.
</summary>
</member>
</members> </members>
</doc> </doc>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册