mirror of
https://gitee.com/dotnetchina/anno.core.git
synced 2025-12-06 08:48:50 +08:00
重构目录
This commit is contained in:
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
*/bin
|
||||
*/obj
|
||||
*/Release
|
||||
/.vs/config/applicationhost.config
|
||||
/.vs/Anno/v15/.suo
|
||||
/.vs/Anno/v15/sqlite3/storage.ide
|
||||
*.AssemblyInfo.cs
|
||||
*.pubxml
|
||||
*.lock
|
||||
*.ide
|
||||
*.user
|
||||
/*/*/obj/
|
||||
/*/*/bin/
|
||||
/*/*/*/obj/
|
||||
/*/*/*/bin/
|
||||
/.vs/Anno/v15/Server/sqlite3/*.ide-shm
|
||||
/.vs/Anno/v15/Server/sqlite3/*.ide-wal
|
||||
/*/*/obj
|
||||
/.vs/Anno/lut
|
||||
/DCS/AppService/Packages/
|
||||
/.vs/Anno/DesignTimeBuild/.dtbcache
|
||||
/.vs/Anno/v16/.suo
|
||||
/.vs/Anno/v16/Server/sqlite3/storage.ide-shm
|
||||
/.vs/Anno/v16/Server/sqlite3/storage.ide-wal
|
||||
/.vs/Anno/v16/TestStore/0/000-0000.testlog
|
||||
/.vs/Anno/v16/TestStore/0/testlog.manifest
|
||||
/.vs/Anno.Core/DesignTimeBuild/.dtbcache.v2
|
||||
/.vs/Anno.Core/v16/.suo
|
||||
/.vs/Anno.Core/v16/suoF487.tmp
|
||||
/src/*/*/*/obj
|
||||
/src/*/*/*/bin
|
||||
/samples/*/*/obj
|
||||
/samples/*/*/bin
|
||||
217
Anno.Core.sln
Normal file
217
Anno.Core.sln
Normal file
@@ -0,0 +1,217 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30611.23
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Const", "src\Anno.Const\Anno.Const.csproj", "{72002C37-BBC4-43EA-82E0-C7205F5A18A1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Log", "src\Anno.Log\Anno.Log.csproj", "{9D9BF405-D966-4345-87EF-7031FB56F914}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Loader", "src\Anno.Loader\Anno.Loader.csproj", "{16054712-4822-41BD-96A7-A17CA01E0836}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.CronNET", "src\Anno.CronNET\Anno.CronNET.csproj", "{3CD1A9D4-5D61-4CE4-ADC0-13646AC165A7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.EngineData", "src\Anno.EngineData\Anno.EngineData.csproj", "{CF8C6C6F-F259-4227-B2F7-9E7E03D59A74}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9FFB057D-707E-464D-9C1E-4BFBBD22AC93}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Rpc.Center", "src\Core\Anno.Rpc.Center\Anno.Rpc.Center.csproj", "{6F070C23-A0F1-4B7C-9E2A-5235CCE6F6C1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Rpc.Client", "src\Core\Anno.Rpc.Client\Anno.Rpc.Client.csproj", "{3BB97F09-EF42-49E5-8BA8-656478C72A02}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Rpc.Server", "src\Core\Anno.Rpc.Server\Anno.Rpc.Server.csproj", "{3D39EC98-C316-4B4F-95D2-C0DDB39C993A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Grpc", "Grpc", "{9D8DA6E9-587C-4685-A83A-71BC31BF9A86}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Rpc.CenterGrpc", "src\Core\Grpc\Anno.Rpc.Center\Anno.Rpc.CenterGrpc.csproj", "{0850FC60-C0B1-4DEA-AC62-74BBE9B17732}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Rpc.ClientGrpc", "src\Core\Grpc\Anno.Rpc.Client\Anno.Rpc.ClientGrpc.csproj", "{4D33539F-1BD3-4CE0-8F1E-AFD3B2EB7CD1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Rpc.ServerGrpc", "src\Core\Grpc\Anno.Rpc.Server\Anno.Rpc.ServerGrpc.csproj", "{014FCB6B-CD70-4491-8E2D-FAE5F1DFFA1E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{1CB9768D-3941-4FE0-99E8-7FD319A959A3}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B1D75545-FB2B-445F-AE77-6B9EB5906E2F}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
test\annoTest.bat = test\annoTest.bat
|
||||
test\annoTestRelease.bat = test\annoTestRelease.bat
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Thrift", "Thrift", "{118EC682-0C63-4EDF-A192-49607FB665F2}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
samples\Thrift\annoCenter.bat = samples\Thrift\annoCenter.bat
|
||||
samples\Thrift\annoCenterRelease.bat = samples\Thrift\annoCenterRelease.bat
|
||||
samples\Thrift\annoService.bat = samples\Thrift\annoService.bat
|
||||
samples\Thrift\annoServiceRelease.bat = samples\Thrift\annoServiceRelease.bat
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Grpc", "Grpc", "{4182479F-7B50-4B51-80FD-7EED6C3A1A84}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnnoCenter", "samples\Thrift\AnnoCenter\AnnoCenter.csproj", "{3E972B44-A51F-40BE-ABA5-D60EFCCC344E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnnoService", "samples\Thrift\AnnoService\AnnoService.csproj", "{255EA20C-5E2C-447F-98D0-E2B8F98FC366}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnnoCenter", "samples\Grpc\AnnoCenter\AnnoCenter.csproj", "{845DFC0C-DBF4-4080-BDDD-70F059EC54B0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnnoService", "samples\Grpc\AnnoService\AnnoService.csproj", "{34D91175-933D-4EFC-B021-6933717A41C8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{5EE94D38-77C8-422C-9E1B-23CBDCFFBA0E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWorldDto", "samples\Packages\HelloWorldDto\HelloWorldDto.csproj", "{E67EEC45-7591-4B3B-BE59-52C2C7A8E514}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Plugs.HelloWorldService", "samples\Packages\Anno.Plugs.HelloWorldService\Anno.Plugs.HelloWorldService.csproj", "{45FE5691-32D0-4DB7-B60C-8CBE534CE1F7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Plugs.SoEasyService", "samples\Packages\Anno.Plugs.SoEasyService\Anno.Plugs.SoEasyService.csproj", "{F0B8E8BF-3736-4629-9F4F-866FABA780F6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Plugs.TraceService", "samples\Packages\Anno.Plugs.TraceService\Anno.Plugs.TraceService.csproj", "{DBF77683-1694-47B0-8650-400B82F240B7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Plugs.DLockService", "samples\Packages\Anno.Plugs.DLockService\Anno.Plugs.DLockService.csproj", "{221BE57F-E0ED-46CC-A8CB-9EB87EE7E688}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTest", "test\ConsoleTest\ConsoleTest.csproj", "{523E3383-4FE4-4F02-A37F-B4E86BB8A030}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anno.Test", "test\Anno.Test\Anno.Test.csproj", "{432C0AF6-9E06-4FB5-B678-8884F5106CD1}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "builder", "builder", "{019EA972-EEAE-4F22-9DA8-9E79731927CF}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Directory.Build.props = Directory.Build.props
|
||||
logo.jpg = logo.jpg
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{3EA5B10B-B18A-4913-9143-834A1C6DEC56}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{E07F4903-4978-463B-B17F-B9E3C8166920}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{72002C37-BBC4-43EA-82E0-C7205F5A18A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{72002C37-BBC4-43EA-82E0-C7205F5A18A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{72002C37-BBC4-43EA-82E0-C7205F5A18A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{72002C37-BBC4-43EA-82E0-C7205F5A18A1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9D9BF405-D966-4345-87EF-7031FB56F914}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9D9BF405-D966-4345-87EF-7031FB56F914}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9D9BF405-D966-4345-87EF-7031FB56F914}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9D9BF405-D966-4345-87EF-7031FB56F914}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{16054712-4822-41BD-96A7-A17CA01E0836}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16054712-4822-41BD-96A7-A17CA01E0836}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16054712-4822-41BD-96A7-A17CA01E0836}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16054712-4822-41BD-96A7-A17CA01E0836}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3CD1A9D4-5D61-4CE4-ADC0-13646AC165A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3CD1A9D4-5D61-4CE4-ADC0-13646AC165A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3CD1A9D4-5D61-4CE4-ADC0-13646AC165A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3CD1A9D4-5D61-4CE4-ADC0-13646AC165A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CF8C6C6F-F259-4227-B2F7-9E7E03D59A74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CF8C6C6F-F259-4227-B2F7-9E7E03D59A74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CF8C6C6F-F259-4227-B2F7-9E7E03D59A74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CF8C6C6F-F259-4227-B2F7-9E7E03D59A74}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6F070C23-A0F1-4B7C-9E2A-5235CCE6F6C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6F070C23-A0F1-4B7C-9E2A-5235CCE6F6C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6F070C23-A0F1-4B7C-9E2A-5235CCE6F6C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6F070C23-A0F1-4B7C-9E2A-5235CCE6F6C1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3BB97F09-EF42-49E5-8BA8-656478C72A02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3BB97F09-EF42-49E5-8BA8-656478C72A02}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3BB97F09-EF42-49E5-8BA8-656478C72A02}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3BB97F09-EF42-49E5-8BA8-656478C72A02}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D39EC98-C316-4B4F-95D2-C0DDB39C993A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D39EC98-C316-4B4F-95D2-C0DDB39C993A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D39EC98-C316-4B4F-95D2-C0DDB39C993A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D39EC98-C316-4B4F-95D2-C0DDB39C993A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0850FC60-C0B1-4DEA-AC62-74BBE9B17732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0850FC60-C0B1-4DEA-AC62-74BBE9B17732}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0850FC60-C0B1-4DEA-AC62-74BBE9B17732}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0850FC60-C0B1-4DEA-AC62-74BBE9B17732}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4D33539F-1BD3-4CE0-8F1E-AFD3B2EB7CD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4D33539F-1BD3-4CE0-8F1E-AFD3B2EB7CD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4D33539F-1BD3-4CE0-8F1E-AFD3B2EB7CD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4D33539F-1BD3-4CE0-8F1E-AFD3B2EB7CD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{014FCB6B-CD70-4491-8E2D-FAE5F1DFFA1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{014FCB6B-CD70-4491-8E2D-FAE5F1DFFA1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{014FCB6B-CD70-4491-8E2D-FAE5F1DFFA1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{014FCB6B-CD70-4491-8E2D-FAE5F1DFFA1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3E972B44-A51F-40BE-ABA5-D60EFCCC344E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3E972B44-A51F-40BE-ABA5-D60EFCCC344E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3E972B44-A51F-40BE-ABA5-D60EFCCC344E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3E972B44-A51F-40BE-ABA5-D60EFCCC344E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{255EA20C-5E2C-447F-98D0-E2B8F98FC366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{255EA20C-5E2C-447F-98D0-E2B8F98FC366}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{255EA20C-5E2C-447F-98D0-E2B8F98FC366}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{255EA20C-5E2C-447F-98D0-E2B8F98FC366}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{845DFC0C-DBF4-4080-BDDD-70F059EC54B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{845DFC0C-DBF4-4080-BDDD-70F059EC54B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{845DFC0C-DBF4-4080-BDDD-70F059EC54B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{845DFC0C-DBF4-4080-BDDD-70F059EC54B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{34D91175-933D-4EFC-B021-6933717A41C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{34D91175-933D-4EFC-B021-6933717A41C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{34D91175-933D-4EFC-B021-6933717A41C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{34D91175-933D-4EFC-B021-6933717A41C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E67EEC45-7591-4B3B-BE59-52C2C7A8E514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E67EEC45-7591-4B3B-BE59-52C2C7A8E514}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E67EEC45-7591-4B3B-BE59-52C2C7A8E514}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E67EEC45-7591-4B3B-BE59-52C2C7A8E514}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{45FE5691-32D0-4DB7-B60C-8CBE534CE1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{45FE5691-32D0-4DB7-B60C-8CBE534CE1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{45FE5691-32D0-4DB7-B60C-8CBE534CE1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{45FE5691-32D0-4DB7-B60C-8CBE534CE1F7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F0B8E8BF-3736-4629-9F4F-866FABA780F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F0B8E8BF-3736-4629-9F4F-866FABA780F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F0B8E8BF-3736-4629-9F4F-866FABA780F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F0B8E8BF-3736-4629-9F4F-866FABA780F6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DBF77683-1694-47B0-8650-400B82F240B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DBF77683-1694-47B0-8650-400B82F240B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DBF77683-1694-47B0-8650-400B82F240B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DBF77683-1694-47B0-8650-400B82F240B7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{221BE57F-E0ED-46CC-A8CB-9EB87EE7E688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{221BE57F-E0ED-46CC-A8CB-9EB87EE7E688}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{221BE57F-E0ED-46CC-A8CB-9EB87EE7E688}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{221BE57F-E0ED-46CC-A8CB-9EB87EE7E688}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{523E3383-4FE4-4F02-A37F-B4E86BB8A030}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{523E3383-4FE4-4F02-A37F-B4E86BB8A030}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{523E3383-4FE4-4F02-A37F-B4E86BB8A030}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{523E3383-4FE4-4F02-A37F-B4E86BB8A030}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{432C0AF6-9E06-4FB5-B678-8884F5106CD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{432C0AF6-9E06-4FB5-B678-8884F5106CD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{432C0AF6-9E06-4FB5-B678-8884F5106CD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{432C0AF6-9E06-4FB5-B678-8884F5106CD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{72002C37-BBC4-43EA-82E0-C7205F5A18A1} = {9FFB057D-707E-464D-9C1E-4BFBBD22AC93}
|
||||
{9D9BF405-D966-4345-87EF-7031FB56F914} = {9FFB057D-707E-464D-9C1E-4BFBBD22AC93}
|
||||
{16054712-4822-41BD-96A7-A17CA01E0836} = {9FFB057D-707E-464D-9C1E-4BFBBD22AC93}
|
||||
{3CD1A9D4-5D61-4CE4-ADC0-13646AC165A7} = {9FFB057D-707E-464D-9C1E-4BFBBD22AC93}
|
||||
{CF8C6C6F-F259-4227-B2F7-9E7E03D59A74} = {9FFB057D-707E-464D-9C1E-4BFBBD22AC93}
|
||||
{6F070C23-A0F1-4B7C-9E2A-5235CCE6F6C1} = {3EA5B10B-B18A-4913-9143-834A1C6DEC56}
|
||||
{3BB97F09-EF42-49E5-8BA8-656478C72A02} = {3EA5B10B-B18A-4913-9143-834A1C6DEC56}
|
||||
{3D39EC98-C316-4B4F-95D2-C0DDB39C993A} = {3EA5B10B-B18A-4913-9143-834A1C6DEC56}
|
||||
{9D8DA6E9-587C-4685-A83A-71BC31BF9A86} = {3EA5B10B-B18A-4913-9143-834A1C6DEC56}
|
||||
{0850FC60-C0B1-4DEA-AC62-74BBE9B17732} = {9D8DA6E9-587C-4685-A83A-71BC31BF9A86}
|
||||
{4D33539F-1BD3-4CE0-8F1E-AFD3B2EB7CD1} = {9D8DA6E9-587C-4685-A83A-71BC31BF9A86}
|
||||
{014FCB6B-CD70-4491-8E2D-FAE5F1DFFA1E} = {9D8DA6E9-587C-4685-A83A-71BC31BF9A86}
|
||||
{118EC682-0C63-4EDF-A192-49607FB665F2} = {1CB9768D-3941-4FE0-99E8-7FD319A959A3}
|
||||
{4182479F-7B50-4B51-80FD-7EED6C3A1A84} = {1CB9768D-3941-4FE0-99E8-7FD319A959A3}
|
||||
{3E972B44-A51F-40BE-ABA5-D60EFCCC344E} = {118EC682-0C63-4EDF-A192-49607FB665F2}
|
||||
{255EA20C-5E2C-447F-98D0-E2B8F98FC366} = {118EC682-0C63-4EDF-A192-49607FB665F2}
|
||||
{845DFC0C-DBF4-4080-BDDD-70F059EC54B0} = {4182479F-7B50-4B51-80FD-7EED6C3A1A84}
|
||||
{34D91175-933D-4EFC-B021-6933717A41C8} = {4182479F-7B50-4B51-80FD-7EED6C3A1A84}
|
||||
{5EE94D38-77C8-422C-9E1B-23CBDCFFBA0E} = {1CB9768D-3941-4FE0-99E8-7FD319A959A3}
|
||||
{E67EEC45-7591-4B3B-BE59-52C2C7A8E514} = {5EE94D38-77C8-422C-9E1B-23CBDCFFBA0E}
|
||||
{45FE5691-32D0-4DB7-B60C-8CBE534CE1F7} = {5EE94D38-77C8-422C-9E1B-23CBDCFFBA0E}
|
||||
{F0B8E8BF-3736-4629-9F4F-866FABA780F6} = {5EE94D38-77C8-422C-9E1B-23CBDCFFBA0E}
|
||||
{DBF77683-1694-47B0-8650-400B82F240B7} = {5EE94D38-77C8-422C-9E1B-23CBDCFFBA0E}
|
||||
{221BE57F-E0ED-46CC-A8CB-9EB87EE7E688} = {5EE94D38-77C8-422C-9E1B-23CBDCFFBA0E}
|
||||
{523E3383-4FE4-4F02-A37F-B4E86BB8A030} = {B1D75545-FB2B-445F-AE77-6B9EB5906E2F}
|
||||
{432C0AF6-9E06-4FB5-B678-8884F5106CD1} = {B1D75545-FB2B-445F-AE77-6B9EB5906E2F}
|
||||
{3EA5B10B-B18A-4913-9143-834A1C6DEC56} = {9FFB057D-707E-464D-9C1E-4BFBBD22AC93}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {CF1BE717-8264-4D74-AEED-B289CDEDD42F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
8
Directory.Build.props
Normal file
8
Directory.Build.props
Normal file
@@ -0,0 +1,8 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<DeveloperBuildCoreTfms>netcoreapp3.1</DeveloperBuildCoreTfms>
|
||||
<StandardTfms>netstandard2.0</StandardTfms>
|
||||
<Version>1.0.2.6</Version>
|
||||
<PackageIconUrl>http://140.143.207.244/img/logo.jpg</PackageIconUrl>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
201
LICENSE
Normal file
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 杜燕明
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
196
README.md
Normal file
196
README.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# Anno 分布式微服务开发框架
|
||||
|
||||

|
||||
|
||||
[在线演示](http://140.143.207.244) :http://140.143.207.244
|
||||
|
||||
[示例项目Viper](https://github.com/duyanming/Viper) :https://github.com/duyanming/Viper
|
||||
### Anno 是一个分布式开发框架,专注于服务治理、监控、链路追踪。RPC可选用高性能跨语言的Thrift(推荐)、Grpc。同时支持 .net core 、.net framework。
|
||||
|
||||
## 整体架构
|
||||
|
||||
整体架构主要分为三个部分
|
||||
|
||||
1、注册中心:AnnoCenter
|
||||
|
||||
2、服务宿主程序:AnnoService(可以是多个服务例如:订单服务A、库存服务B、支付服务C、用户服务D)
|
||||
|
||||
3、ApiGateway:[参考Viper](https://github.com/duyanming/Viper)
|
||||
|
||||
|
||||
# 主要功能
|
||||
|
||||
服务注册中心、服务发现、健康检查、负载均衡、限流、失败重试、链路追踪等功能
|
||||
|
||||
|
||||
# 注册中心-AnnoCenter
|
||||
|
||||
AnnoCenter 是一个服务注册中心,主要职责是 发现服务(例如订单服务A、库存服务B)、保存服务配置信息、健康检查、简单键值KV存储。客户端为定时从注册中心取服务信息缓存到本地。即便注册中心宕机也不影响整个集群运行,因为客户端已经缓存了整个集群的服务信息,但是新加入的服务无法注册进来,需要启动注册中心才可以。
|
||||
客户端(例如:ApiGateway )发送过来请求时,客户端类库从本地缓存找出能够处理此请求的服务列表(这个过程可能涉及权重等策略)选择一个去处理请求,然后返回,如果失败会有重试机制。
|
||||
注册中心会对每个服务定时做健康检查,如果连接不上服务则标记此服务为亚健康状态,此时不会将此服务立即踢出,此时开始重复做检查。如果一分钟内恢复正常则重新标记为健康状态,否则永久踢出服务。
|
||||
|
||||
|
||||
服务注册中心(AnnoCenter) 是整个集群第一个需要运行起来的程序。
|
||||
|
||||
配置文件:只需要配置端口、超时时间即可。服务节点信息会在服务注册进来的时候自动写入
|
||||
|
||||
```xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<!--#lbs 配置 Port 注册中心监听端口 TimeOut 超时时间毫秒
|
||||
dc:节点
|
||||
dc:nickname:服务名称 App001
|
||||
dc:name: 功能tag
|
||||
dc:ip:服务IP
|
||||
dc:port:服务端口
|
||||
dc:timeout:服务超时时间
|
||||
dc:weight:服务权重 数字
|
||||
-->
|
||||
<Port>6660</Port>
|
||||
<TimeOut>120000</TimeOut>
|
||||
<Servers>
|
||||
<dc name="Anno.Plugs.TraceService,Anno.Plugs.DLockService,Anno.Plugs.EsLogService" nickname="App001" ip="10.112.93.122" port="6659" timeout="20000" weight="1" />
|
||||
</Servers>
|
||||
</configuration>
|
||||
|
||||
```
|
||||
|
||||
# 服务-AnnoService
|
||||
服务宿主程序,本着约定大于配置的开发原则。
|
||||
插件式开发具体参考:
|
||||
Packages
|
||||
Anno.Plugs.HelloWorldService
|
||||
初始化配置
|
||||
实现接口:IPlugsConfigurationBootstrap
|
||||
|
||||
```cs
|
||||
using Anno.EngineData;
|
||||
using System;
|
||||
|
||||
namespace Anno.Plugs.HelloWorldService
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件启动引导器
|
||||
/// DependsOn 依赖的类型程序集自动注入DI容器
|
||||
/// </summary>
|
||||
[DependsOn(
|
||||
//typeof(Domain.Bootstrap)
|
||||
//, typeof(QueryServices.Bootstrap)
|
||||
//, typeof(Repository.Bootstrap)
|
||||
//, typeof(Command.Handler.Bootstrap
|
||||
)]
|
||||
public class HelloWorldBootStrap : IPlugsConfigurationBootstrap
|
||||
{
|
||||
/// <summary>
|
||||
/// Service 依赖注入构建之后调用
|
||||
/// </summary>
|
||||
public void ConfigurationBootstrap()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
/// <summary>
|
||||
/// Service 依赖注入构建之前调用
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
public void PreConfigurationBootstrap()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
功能模块实现
|
||||
继承: BaseModule
|
||||
|
||||
```cs
|
||||
/******************************************************
|
||||
Writer:Du YanMing
|
||||
Mail:dym880@163.com
|
||||
Create Date:2020/10/30 13:15:24
|
||||
Functional description: HelloWorldViperModule
|
||||
******************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Plugs.HelloWorldService
|
||||
{
|
||||
using Anno.Const.Attribute;
|
||||
using Anno.EngineData;
|
||||
using HelloWorldDto;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class HelloWorldViperModule : BaseModule
|
||||
{
|
||||
[AnnoInfo(Desc = "世界你好啊SayHi")]
|
||||
public dynamic SayHello([AnnoInfo(Desc = "称呼")] string name, [AnnoInfo(Desc = "年龄")] int age)
|
||||
{
|
||||
Dictionary<string, string> input = new Dictionary<string, string>();
|
||||
input.Add("vname", name);
|
||||
input.Add("vage", age.ToString());
|
||||
var soEasyMsg = Newtonsoft.Json.JsonConvert.DeserializeObject<ActionResult<string>>(this.InvokeProcessor("Anno.Plugs.SoEasy", "AnnoSoEasy", "SayHi", input)).OutputData;
|
||||
return new { HelloWorldViperMsg = $"{name}你好啊,今年{age}岁了", SoEasyMsg = soEasyMsg };
|
||||
}
|
||||
|
||||
[AnnoInfo(Desc = "两个整数相减等于几?我来帮你算(x-y=?)")]
|
||||
public int Subtraction([AnnoInfo(Desc = "整数X")] int x, [AnnoInfo(Desc = "整数Y")] int y)
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
[AnnoInfo(Desc = "买个商品吧,双十一马上就来了")]
|
||||
public ProductDto BuyProduct([AnnoInfo(Desc = "商品名称")] string productName, [AnnoInfo(Desc = "商品数量")] int number)
|
||||
{
|
||||
double price = new Random().Next(2, 90);
|
||||
Dictionary<string, string> input = new Dictionary<string, string>();
|
||||
input.Add("productName", productName);
|
||||
input.Add("number", number.ToString());
|
||||
var product = Newtonsoft.Json.JsonConvert.DeserializeObject<ActionResult<ProductDto>>(this.InvokeProcessor("Anno.Plugs.SoEasy", "AnnoSoEasy", "BuyProduct", input)).OutputData;
|
||||
product.CountryOfOrigin = $"中国北京中转--{ product.CountryOfOrigin}";
|
||||
return product;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
配置文件:
|
||||
```xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<!--0,0 第一位是 工作站,第二位数据中心
|
||||
(所有的 AnnoService 的 两位数不能重复例如不能存在【1,2】【1,2】)
|
||||
可以存在【1,2】【2,1】
|
||||
-->
|
||||
<IdWorker>0,0</IdWorker>
|
||||
<!--App名称-->
|
||||
<AppName>App001</AppName>
|
||||
<!--监听端口-->
|
||||
<Port>6659</Port>
|
||||
<!--权重-->
|
||||
<Weight>1</Weight>
|
||||
<!--功能-->
|
||||
<FuncName>Anno.Plugs.LogicService,Anno.Plugs.TraceService</FuncName>
|
||||
<!--忽略的功能 Trace,Logic-->
|
||||
<IgnoreFuncName></IgnoreFuncName>
|
||||
<!--超时时间毫秒-->
|
||||
<TimeOut>20000</TimeOut>
|
||||
<!--注册到的目标-->
|
||||
<Ts Ip="10.112.93.122" Port="6660"/>
|
||||
<IocDll>
|
||||
<!-- IOC 仓储、领域-->
|
||||
<Assembly>Anno.Repository</Assembly>
|
||||
</IocDll>
|
||||
<appSettings>
|
||||
|
||||
</appSettings>
|
||||
</configuration>
|
||||
|
||||
```
|
||||
|
||||
# 网关
|
||||
|
||||
[参考Viper](https://github.com/duyanming/Viper)
|
||||
9
samples/Grpc/AnnoCenter/Anno.config
Normal file
9
samples/Grpc/AnnoCenter/Anno.config
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<!--#lbs 配置-->
|
||||
<Port>6660</Port>
|
||||
<TimeOut>120000</TimeOut>
|
||||
<Servers>
|
||||
|
||||
</Servers>
|
||||
</configuration>
|
||||
1
samples/Grpc/AnnoCenter/AnnoCenter.bat
Normal file
1
samples/Grpc/AnnoCenter/AnnoCenter.bat
Normal file
@@ -0,0 +1 @@
|
||||
dotnet AnnoCenter.dll
|
||||
32
samples/Grpc/AnnoCenter/AnnoCenter.csproj
Normal file
32
samples/Grpc/AnnoCenter/AnnoCenter.csproj
Normal file
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>$(DeveloperBuildCoreTfms)</TargetFramework>
|
||||
<Authors>杜燕明</Authors>
|
||||
<Company>杜燕明</Company>
|
||||
<Version>1.0.0.1</Version>
|
||||
<!--win-x86;win-x64;linux-x64;osx-x64-->
|
||||
<!--<RuntimeIdentifiers>win-x86</RuntimeIdentifiers>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Core\Grpc\Anno.Rpc.Center\Anno.Rpc.CenterGrpc.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="AnnoCenter.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Anno.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="stop.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="start.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
18
samples/Grpc/AnnoCenter/Program.cs
Normal file
18
samples/Grpc/AnnoCenter/Program.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AnnoCenter
|
||||
{
|
||||
using Anno.Rpc.Center;
|
||||
static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.Title = "AnnoCenter";
|
||||
Bootstrap.StartUp(args);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
samples/Grpc/AnnoCenter/ddcenter.sh
Normal file
11
samples/Grpc/AnnoCenter/ddcenter.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
if [ $1 == "start" ];then
|
||||
nohup dotnet AnnoCenter.dll 2>&1 &
|
||||
echo "$!" > pid
|
||||
echo "start ok!"
|
||||
elif [ $1 == "stop" ];then
|
||||
kill `cat pid`
|
||||
echo "stop ok!"
|
||||
else
|
||||
echo "Please make sure the position variable is start or stop."
|
||||
fi
|
||||
53
samples/Grpc/AnnoService/Anno.config
Normal file
53
samples/Grpc/AnnoService/Anno.config
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<!--0,0 第一位是 工作站,第二位数据中心
|
||||
(所有的 AnnoService 的 两位数不能重复例如不能存在【1,2】【1,2】)
|
||||
可以存在【1,2】【2,1】
|
||||
-->
|
||||
<IdWorker>0,0</IdWorker>
|
||||
<!--App名称-->
|
||||
<AppName>App001</AppName>
|
||||
<!--监听端口-->
|
||||
<Port>6659</Port>
|
||||
<!--权重-->
|
||||
<Weight>1</Weight>
|
||||
<!--功能 非Anno.Plugs 加入方式-->
|
||||
<FuncName></FuncName>
|
||||
<!--忽略的功能 Trace,Logic-->
|
||||
<IgnoreFuncName></IgnoreFuncName>
|
||||
<!--超时时间毫秒-->
|
||||
<TimeOut>20000</TimeOut>
|
||||
<!--注册到的目标-->
|
||||
<Ts Ip="127.0.0.1" Port="6660"/>
|
||||
<IocDll>
|
||||
<!-- IOC 仓储--><!--
|
||||
<Assembly>Anno.Repository</Assembly>
|
||||
--><!-- 领域--><!--
|
||||
<Assembly>Anno.Domain</Assembly>
|
||||
--><!-- 查询服务--><!--
|
||||
<Assembly>Anno.QueryServices</Assembly>
|
||||
--><!--事件Handler--><!--
|
||||
<Assembly>Anno.Command.Handler</Assembly>-->
|
||||
</IocDll>
|
||||
<appSettings>
|
||||
<!-- 数据库连接字符串 Mysql-->
|
||||
<add key="ConnStr" value="server=127.0.0.1;database=bif;uid=bif;pwd=123456;SslMode=None;"/>
|
||||
<!--重置默认密码-->
|
||||
<add key="DefaultPwd" value="123456"/>
|
||||
<!--
|
||||
redisConn Redis 连接字符串
|
||||
redisPrefix Key 前缀
|
||||
redisExpiryDate Key 有效期 单位(分钟)
|
||||
redisSwitch 是否开启数据库 false 不开启
|
||||
-->
|
||||
<add key="redisConn" value="127.0.0.1:6379,abortConnect=false,allowAdmin =true,keepAlive=180"/>
|
||||
<add key="redisPrefix" value="Anno:"/>
|
||||
<add key="redisExpiryDate" value="20"/>
|
||||
<add key="redisSwitch" value="false"/>
|
||||
<!--MongoDB 配置-->
|
||||
<add key="MongoConn" value="mongodb://192.168.1.2"/>
|
||||
<add key="MongodName" value="bif"/>
|
||||
</appSettings>
|
||||
<!--RabbitMQ 配置-->
|
||||
<RabbitMQ key="RabbitMQ" HostName="10.10.10.39" UserName="bsc" Password="bsc$15" VirtualHost="test" Port="5672"/>
|
||||
</configuration>
|
||||
1
samples/Grpc/AnnoService/AnnoService.bat
Normal file
1
samples/Grpc/AnnoService/AnnoService.bat
Normal file
@@ -0,0 +1 @@
|
||||
dotnet AnnoService.dll
|
||||
42
samples/Grpc/AnnoService/AnnoService.csproj
Normal file
42
samples/Grpc/AnnoService/AnnoService.csproj
Normal file
@@ -0,0 +1,42 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win10-x64;</RuntimeIdentifiers>
|
||||
<TargetFrameworks>$(DeveloperBuildCoreTfms);net461</TargetFrameworks>
|
||||
<Authors>杜燕明</Authors>
|
||||
<Company>杜燕明</Company>
|
||||
<Version>1.0.0.1</Version>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Packages\Plugs插件使用说明.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="start.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="AnnoService.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Anno.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="stop.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Packages\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Core\Grpc\Anno.Rpc.Server\Anno.Rpc.ServerGrpc.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.DLockService\Anno.Plugs.DLockService.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.HelloWorldService\Anno.Plugs.HelloWorldService.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.SoEasyService\Anno.Plugs.SoEasyService.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.TraceService\Anno.Plugs.TraceService.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
Plugs插件使用说明
|
||||
|
||||
1、Plugs插件使用说明
|
||||
1.1 插件存放在宿主程序的根目录下的 Packages 文件夹下面。
|
||||
1.2 插件例如【dym.Plugs.SerialRule】序列生成服务 必须以目录形成存在
|
||||
1.3 插件目录结构如下
|
||||
dym.Plugs.SerialRule
|
||||
|
|
||||
dym.Plugs.SerialRuleService.dll
|
||||
1.4 宿主程序会加载插件【XXX】目录【dym.Plugs.XXX】下面的入口文件【dym.Plugs.XXXService.dll】
|
||||
10
samples/Grpc/AnnoService/Packages/Plugs插件使用说明.txt
Normal file
10
samples/Grpc/AnnoService/Packages/Plugs插件使用说明.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Plugs插件使用说明
|
||||
|
||||
1、Plugs插件使用说明
|
||||
1.1 插件存放在宿主程序的根目录下的 Packages 文件夹下面。
|
||||
1.2 插件例如【Anno.Plugs.SerialRule】序列生成服务 必须以目录形成存在
|
||||
1.3 插件目录结构如下
|
||||
Anno.Plugs.SerialRule
|
||||
|
|
||||
Anno.Plugs.SerialRuleService.dll
|
||||
1.4 宿主程序会加载插件【XXX】目录【Anno.Plugs.XXX】下面的入口文件【Anno.Plugs.XXXService.dll】
|
||||
115
samples/Grpc/AnnoService/Program.cs
Normal file
115
samples/Grpc/AnnoService/Program.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Anno.Const.Attribute;
|
||||
using Anno.Loader;
|
||||
using Anno.Log;
|
||||
using Autofac;
|
||||
|
||||
namespace AnnoService
|
||||
{
|
||||
using Anno.EngineData;
|
||||
using Anno.Rpc.Server;
|
||||
using System.Collections.Generic;
|
||||
using Anno.Rpc.Storage;
|
||||
|
||||
static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Contains("-help"))
|
||||
{
|
||||
Log.ConsoleWriteLine(@"
|
||||
启动参数:
|
||||
-p 6659 设置启动端口
|
||||
-xt 200 设置服务最大线程数
|
||||
-t 20000 设置超时时间(单位毫秒)
|
||||
-w 1 设置权重
|
||||
-h 192.168.0.2 设置服务在注册中心的地址
|
||||
-tr false 设置调用链追踪是否启用");
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* 启动默认DI库为 Autofac 可以切换为微软自带的DI库 DependencyInjection
|
||||
*/
|
||||
Bootstrap.StartUp(args, () =>//服务配置文件读取完成后回调(服务未启动)
|
||||
{
|
||||
//Anno.Const.SettingService.TraceOnOff = true;
|
||||
|
||||
/*
|
||||
* 功能插件选择是Thrift还是 Grpc
|
||||
* Install-Package Anno.Rpc.Client -Version 1.0.2.6 Thrift
|
||||
* Install-Package Anno.Rpc.ServerGrpc -Version 1.0.1.5 Grpc
|
||||
* 此处为 Thrift
|
||||
*/
|
||||
var autofac = IocLoader.GetAutoFacContainerBuilder();
|
||||
autofac.RegisterType(typeof(RpcConnectorImpl)).As(typeof(IRpcConnector)).SingleInstance();
|
||||
}
|
||||
, () =>//服务启动后的回调方法
|
||||
{
|
||||
/**
|
||||
* 服务Api文档写入注册中心
|
||||
*/
|
||||
ApiDoc();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///服务启动后将服务Api文档写入注册中心
|
||||
///
|
||||
///增加自己的服务的时候只用复制下面的代码就可以不用做修改
|
||||
/// </summary>
|
||||
static void ApiDoc()
|
||||
{
|
||||
List<AnnoData> routings = new List<AnnoData>();
|
||||
foreach (var item in Anno.EngineData.Routing.Routing.Router)
|
||||
{
|
||||
if (item.Value.RoutMethod.Name == "get_ActionResult")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var parameters = item.Value.RoutMethod.GetParameters().ToList().Select(it =>
|
||||
{
|
||||
var parameter = new ParametersValue
|
||||
{ Name = it.Name, Position = it.Position, ParameterType = it.ParameterType.FullName };
|
||||
var pa = it.GetCustomAttributes<AnnoInfoAttribute>().ToList();
|
||||
if (pa.Any())
|
||||
{
|
||||
parameter.Desc = pa.First().Desc;
|
||||
}
|
||||
return parameter;
|
||||
}).ToList();
|
||||
string methodDesc = String.Empty;
|
||||
var mAnnoInfoAttributes = item.Value.RoutMethod.GetCustomAttributes<AnnoInfoAttribute>().ToList();
|
||||
if (mAnnoInfoAttributes.Count > 0)
|
||||
{
|
||||
methodDesc = mAnnoInfoAttributes.First().Desc;
|
||||
}
|
||||
routings.Add(new AnnoData()
|
||||
{
|
||||
App = Anno.Const.SettingService.AppName,
|
||||
Id = $"{Anno.Const.SettingService.AppName}:{item.Key}",
|
||||
Value = Newtonsoft.Json.JsonConvert.SerializeObject(new DataValue { Desc = methodDesc, Name = item.Value.RoutMethod.Name, Parameters = parameters })
|
||||
});
|
||||
}
|
||||
Dictionary<string, string> input = new Dictionary<string, string>();
|
||||
input.Add(CONST.Opt, CONST.DeleteByApp);
|
||||
input.Add(CONST.App, Anno.Const.SettingService.AppName);
|
||||
var del = Newtonsoft.Json.JsonConvert.DeserializeObject<AnnoDataResult>(StorageEngine.Invoke(input));
|
||||
if (del.Status == false)
|
||||
{
|
||||
Log.Error(del);
|
||||
}
|
||||
input.Clear();
|
||||
input.Add(CONST.Opt, CONST.UpsertBatch);
|
||||
input.Add(CONST.Data, Newtonsoft.Json.JsonConvert.SerializeObject(routings));
|
||||
var rlt = Newtonsoft.Json.JsonConvert.DeserializeObject<AnnoDataResult>(StorageEngine.Invoke(input));
|
||||
if (rlt.Status == false)
|
||||
{
|
||||
Log.Error(rlt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
samples/Grpc/AnnoService/ddservice.sh
Normal file
11
samples/Grpc/AnnoService/ddservice.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
if [ $1 == "start" ];then
|
||||
nohup dotnet AnnoService.dll 2>&1 &
|
||||
echo "$!" > pid
|
||||
echo "start ok!"
|
||||
elif [ $1 == "stop" ];then
|
||||
kill `cat pid`
|
||||
echo "stop ok!"
|
||||
else
|
||||
echo "Please make sure the position variable is start or stop."
|
||||
fi
|
||||
3
samples/Grpc/annoCenter.bat
Normal file
3
samples/Grpc/annoCenter.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoCenter/bin/Debug/netcoreapp3.1
|
||||
dotnet AnnoCenter.dll
|
||||
3
samples/Grpc/annoCenterRelease.bat
Normal file
3
samples/Grpc/annoCenterRelease.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoCenter/bin/Release/netcoreapp3.1
|
||||
dotnet AnnoCenter.dll
|
||||
3
samples/Grpc/annoService.bat
Normal file
3
samples/Grpc/annoService.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoService/bin/Debug/netcoreapp3.1
|
||||
dotnet AnnoService.dll
|
||||
3
samples/Grpc/annoServiceRelease.bat
Normal file
3
samples/Grpc/annoServiceRelease.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoService/bin/Release/netcoreapp3.1
|
||||
dotnet AnnoService.dll
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Anno.EngineData" Version="1.0.2.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Anno.EngineData\Anno.EngineData.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
31
samples/Packages/Anno.Plugs.DLockService/DLockBootstrap.cs
Normal file
31
samples/Packages/Anno.Plugs.DLockService/DLockBootstrap.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Plugs.DLockService
|
||||
{
|
||||
using CronNET;
|
||||
using EngineData;
|
||||
|
||||
public class DLockBootstrap: IPlugsConfigurationBootstrap
|
||||
{
|
||||
private static readonly CronDaemon CronDaemon = new CronDaemon();
|
||||
public void ConfigurationBootstrap()
|
||||
{
|
||||
//分布式所启动配置
|
||||
/*
|
||||
* 每个一段时间检测是否有锁超时,超时则释放锁
|
||||
*/
|
||||
CronDaemon.AddJob("* * * * * ? *", DLockCenter.Detection);
|
||||
if (CronDaemon.Status == DaemonStatus.Stop)
|
||||
{
|
||||
CronDaemon.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void PreConfigurationBootstrap()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
samples/Packages/Anno.Plugs.DLockService/DLockCenter.cs
Normal file
58
samples/Packages/Anno.Plugs.DLockService/DLockCenter.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Anno.Plugs.DLockService
|
||||
{
|
||||
public static class DLockCenter
|
||||
{
|
||||
private static List<LockerQueue> _lockerQueues = new List<LockerQueue>();
|
||||
private static readonly object Lock = new object();
|
||||
|
||||
public static EngineData.ActionResult Enter(LockInfo info)
|
||||
{
|
||||
var locker = _lockerQueues.Find(l => l.MLoker.Key == info.Key);
|
||||
if (locker == null)
|
||||
{
|
||||
lock (Lock)//不同锁共锁---有问题Q
|
||||
{
|
||||
locker = _lockerQueues.Find(l => l.MLoker.Key == info.Key);
|
||||
if (locker == null)
|
||||
{
|
||||
locker = new LockerQueue
|
||||
{
|
||||
MLoker =
|
||||
{
|
||||
Owner = info.Owner,
|
||||
Type = info.Type,
|
||||
Key = info.Key,
|
||||
Time = info.Time,
|
||||
EnterTime = DateTime.Now
|
||||
}
|
||||
};
|
||||
_lockerQueues.Add(locker);
|
||||
}
|
||||
}
|
||||
}
|
||||
return locker.Enter(info);
|
||||
}
|
||||
public static void Free(LockInfo info)
|
||||
{
|
||||
_lockerQueues.Find(l => l.MLoker.Owner == info.Owner)?.Free();
|
||||
}
|
||||
/// <summary>
|
||||
/// 超时直接抛弃
|
||||
/// </summary>
|
||||
public static void Detection()
|
||||
{
|
||||
if (_lockerQueues.Count > 0)
|
||||
{
|
||||
_lockerQueues.Where(l=>l.MLoker.IsTimeOut&&l.MLoker.Type!=ProcessType.Free).ToList().ForEach(l=>l.Detection());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
42
samples/Packages/Anno.Plugs.DLockService/DLockModule.cs
Normal file
42
samples/Packages/Anno.Plugs.DLockService/DLockModule.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Anno.Const.Attribute;
|
||||
using Anno.EngineData;
|
||||
|
||||
namespace Anno.Plugs.DLockService
|
||||
{
|
||||
/// <summary>
|
||||
/// 分布式锁服务
|
||||
/// </summary>
|
||||
public class DLockModule : BaseModule
|
||||
{
|
||||
[AnnoInfo(Desc = "分布式锁服务 获取锁[DLKey][TimeOut:5000][Owner]")]
|
||||
public ActionResult EnterLock()
|
||||
{
|
||||
var dlKey = RequestString("DLKey");
|
||||
var timeOut = RequestInt32("TimeOut")??5000;
|
||||
var owner = RequestString("Owner");
|
||||
var locker=new LockInfo()
|
||||
{
|
||||
Key = dlKey,
|
||||
Time = timeOut,
|
||||
Owner=owner,
|
||||
EnterTime=DateTime.Now,
|
||||
Type=ProcessType.Enter
|
||||
};
|
||||
var rlt = DLockCenter.Enter(locker);
|
||||
return rlt;
|
||||
}
|
||||
[AnnoInfo(Desc = "分布式锁服务 释放锁[DLKey][Owner]")]
|
||||
public ActionResult DisposeLock()
|
||||
{
|
||||
var dlKey = RequestString("DLKey");
|
||||
var owner = RequestString("Owner");
|
||||
var locker = new LockInfo();
|
||||
locker.Key = dlKey;
|
||||
locker.Owner = owner;
|
||||
DLockCenter.Free(locker);
|
||||
return new ActionResult(true, null, null, "DisposeLock Message");
|
||||
}
|
||||
}
|
||||
}
|
||||
29
samples/Packages/Anno.Plugs.DLockService/LockInfo.cs
Normal file
29
samples/Packages/Anno.Plugs.DLockService/LockInfo.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Anno.Plugs.DLockService
|
||||
{
|
||||
public class LockInfo
|
||||
{
|
||||
public string Owner { get; set; }
|
||||
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 进入时间
|
||||
/// </summary>
|
||||
public DateTime EnterTime { get; set; } = DateTime.Now;
|
||||
|
||||
public int Time { get; set; }
|
||||
public AutoResetEvent ResetEvent { get; set; } = new AutoResetEvent(true);
|
||||
|
||||
/// <summary>
|
||||
/// 是否已经超时
|
||||
/// </summary>
|
||||
public bool IsTimeOut => (DateTime.Now-EnterTime).TotalMilliseconds > Time;
|
||||
|
||||
public ProcessType Type { get; set; }
|
||||
}
|
||||
}
|
||||
62
samples/Packages/Anno.Plugs.DLockService/LockerQueue.cs
Normal file
62
samples/Packages/Anno.Plugs.DLockService/LockerQueue.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Anno.EngineData;
|
||||
using Anno.Log;
|
||||
|
||||
namespace Anno.Plugs.DLockService
|
||||
{
|
||||
internal class LockerQueue
|
||||
{
|
||||
private readonly object _lock = new object();
|
||||
public LockerQueue()
|
||||
{
|
||||
}
|
||||
public LockInfo MLoker = new LockInfo();
|
||||
public ActionResult Enter(LockInfo info)
|
||||
{
|
||||
bool result = MLoker.ResetEvent.WaitOne(info.Time);
|
||||
if (result)
|
||||
{
|
||||
MLoker.EnterTime = DateTime.Now;
|
||||
MLoker.Time = info.Time;
|
||||
MLoker.Owner = info.Owner;
|
||||
MLoker.Type = ProcessType.Enter;
|
||||
return new ActionResult(true, null, null, "enter");
|
||||
}
|
||||
return new ActionResult(false, null, null, $"{info.Owner}/{info.Key} timeOut");
|
||||
}
|
||||
/// <summary>
|
||||
/// 释放
|
||||
/// </summary>
|
||||
public void Free()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (MLoker.Type != ProcessType.Free)
|
||||
{
|
||||
MLoker.EnterTime = DateTime.Now;
|
||||
MLoker.Type = ProcessType.Free;
|
||||
MLoker.ResetEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
} /// <summary>
|
||||
/// 超时的时候才释放
|
||||
/// </summary>
|
||||
public void Detection()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (MLoker.IsTimeOut && MLoker.Type != ProcessType.Free)
|
||||
{
|
||||
MLoker.EnterTime = DateTime.Now;
|
||||
MLoker.Type = ProcessType.Free;
|
||||
MLoker.ResetEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
samples/Packages/Anno.Plugs.DLockService/ProcessType.cs
Normal file
21
samples/Packages/Anno.Plugs.DLockService/ProcessType.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Plugs.DLockService
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理方式
|
||||
/// </summary>
|
||||
public enum ProcessType
|
||||
{
|
||||
/// <summary>
|
||||
/// 进入
|
||||
/// </summary>
|
||||
Enter,
|
||||
/// <summary>
|
||||
/// 空闲
|
||||
/// </summary>
|
||||
Free
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Anno.EngineData" Version="1.0.2.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Anno.EngineData\Anno.EngineData.csproj" />
|
||||
<ProjectReference Include="..\HelloWorldDto\HelloWorldDto.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,34 @@
|
||||
using Anno.EngineData;
|
||||
using System;
|
||||
|
||||
namespace Anno.Plugs.HelloWorldService
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件启动引导器
|
||||
/// DependsOn 依赖的类型程序集自动注入DI容器
|
||||
/// </summary>
|
||||
[DependsOn(
|
||||
//typeof(Domain.Bootstrap)
|
||||
//, typeof(QueryServices.Bootstrap)
|
||||
//, typeof(Repository.Bootstrap)
|
||||
//, typeof(Command.Handler.Bootstrap
|
||||
)]
|
||||
public class HelloWorldBootStrap : IPlugsConfigurationBootstrap
|
||||
{
|
||||
/// <summary>
|
||||
/// Service 依赖注入构建之后调用
|
||||
/// </summary>
|
||||
public void ConfigurationBootstrap()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
/// <summary>
|
||||
/// Service 依赖注入构建之前调用
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
public void PreConfigurationBootstrap()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/******************************************************
|
||||
Writer:Du YanMing
|
||||
Mail:dym880@163.com
|
||||
Create Date:2020/10/30 13:15:24
|
||||
Functional description: HelloWorldViperModule
|
||||
******************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Plugs.HelloWorldService
|
||||
{
|
||||
using Anno.Const.Attribute;
|
||||
using Anno.EngineData;
|
||||
using HelloWorldDto;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class HelloWorldViperModule : BaseModule
|
||||
{
|
||||
[AnnoInfo(Desc = "世界你好啊SayHi")]
|
||||
public dynamic SayHello([AnnoInfo(Desc = "称呼")] string name, [AnnoInfo(Desc = "年龄")] int age)
|
||||
{
|
||||
Dictionary<string, string> input = new Dictionary<string, string>();
|
||||
input.Add("vname", name);
|
||||
input.Add("vage", age.ToString());
|
||||
var soEasyMsg = Newtonsoft.Json.JsonConvert.DeserializeObject<ActionResult<string>>(this.InvokeProcessor("Anno.Plugs.SoEasy", "AnnoSoEasy", "SayHi", input)).OutputData;
|
||||
return new { HelloWorldViperMsg = $"{name}你好啊,今年{age}岁了", SoEasyMsg = soEasyMsg };
|
||||
}
|
||||
|
||||
[AnnoInfo(Desc = "两个整数相减等于几?我来帮你算(x-y=?)")]
|
||||
public int Subtraction([AnnoInfo(Desc = "整数X")] int x, [AnnoInfo(Desc = "整数Y")] int y)
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
[AnnoInfo(Desc = "买个商品吧,双十一马上就来了")]
|
||||
public ProductDto BuyProduct([AnnoInfo(Desc = "商品名称")] string productName, [AnnoInfo(Desc = "商品数量")] int number)
|
||||
{
|
||||
double price = new Random().Next(2, 90);
|
||||
Dictionary<string, string> input = new Dictionary<string, string>();
|
||||
input.Add("productName", productName);
|
||||
input.Add("number", number.ToString());
|
||||
var product = Newtonsoft.Json.JsonConvert.DeserializeObject<ActionResult<ProductDto>>(this.InvokeProcessor("Anno.Plugs.SoEasy", "AnnoSoEasy", "BuyProduct", input)).OutputData;
|
||||
product.CountryOfOrigin = $"中国北京中转--{ product.CountryOfOrigin}";
|
||||
return product;
|
||||
}
|
||||
#region 测试接口
|
||||
[AnnoInfo(Desc = "测试接口(模拟等待,返回等待毫秒数)")]
|
||||
public ActionResult Test()
|
||||
{
|
||||
var i = new Random().Next(1, 80);
|
||||
System.Threading.Tasks.Task.Delay(i).Wait();//等待1秒
|
||||
return new ActionResult(true, i + " :Test");
|
||||
}
|
||||
[AnnoInfo(Desc = "测试接口(返回true)")]
|
||||
public ActionResult Test0()
|
||||
{
|
||||
return new ActionResult(true);
|
||||
}
|
||||
[AnnoInfo(Desc = "测试接口({Id} From Server Test1.)")]
|
||||
public ActionResult Test1([AnnoInfo(Desc = "Id")] string id)
|
||||
{
|
||||
return new ActionResult(true, id + " From Server Test1.");
|
||||
}
|
||||
[AnnoInfo(Desc = "测试属性校验接口(名称字段【Name】必须输入、年龄有效范围0-150)")]
|
||||
public ActionResult Test2([AnnoInfo(Desc = "接收输入对象")] TestDto dto)
|
||||
{
|
||||
var vrlt = dto.IsValid();
|
||||
if (!vrlt.IsVaild)
|
||||
{
|
||||
return new ActionResult(false, vrlt.ErrorMembers);
|
||||
}
|
||||
return new ActionResult(true, "OK Test2");
|
||||
}
|
||||
[AnnoInfo(Desc = "测试属性校验接口[FromBody](名称字段【Name】必须输入、年龄有效范围0-150)")]
|
||||
public ActionResult TestFb([FromBody] TestDto dto)
|
||||
{
|
||||
var vrlt = dto.IsValid();
|
||||
if (!vrlt.IsVaild)
|
||||
{
|
||||
return new ActionResult(false, vrlt.ErrorMembers);
|
||||
}
|
||||
return new ActionResult(true, "TestFb");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
public class TestDto
|
||||
{
|
||||
[Required(ErrorMessage = "名称字段【Name】必须输入")]
|
||||
public string Name { get; set; }
|
||||
[Range(0, 150, ErrorMessage = "年龄有效范围0-150")]
|
||||
public int Age { get; set; }
|
||||
|
||||
public DateTime Birthday { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Anno.EngineData" Version="1.0.2.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Anno.EngineData\Anno.EngineData.csproj" />
|
||||
<ProjectReference Include="..\HelloWorldDto\HelloWorldDto.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,62 @@
|
||||
/******************************************************
|
||||
Writer:Du YanMing
|
||||
Mail:dym880@163.com
|
||||
Create Date:2020/10/30 13:16:23
|
||||
Functional description: AnnoSoEasyModule
|
||||
******************************************************/
|
||||
using Anno.EngineData;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Plugs.SoEasyService
|
||||
{
|
||||
using Anno.Const.Attribute;
|
||||
using Anno.EngineData;
|
||||
using HelloWorldDto;
|
||||
|
||||
public class AnnoSoEasyModule : BaseModule
|
||||
{
|
||||
[AnnoInfo(Desc = "AnnoSoEasy你好啊SayHi")]
|
||||
public dynamic SayHi([AnnoInfo(Desc = "称呼")] string vname, [AnnoInfo(Desc = "年龄")] int vage)
|
||||
{
|
||||
var msg = string.Empty;
|
||||
if (vage < 12)
|
||||
{
|
||||
msg = "小朋友年纪轻轻就就开始玩编程了啊!加油Baby!";
|
||||
}else if (vage < 23)
|
||||
{
|
||||
msg = "小兄弟,找女朋友了吗?没有的话赶紧找一个吧。别把心思都放在写代码上!";
|
||||
}
|
||||
else if (vage < 30)
|
||||
{
|
||||
msg = "兄弟,你家小孩几岁了?开始学编程了吗?";
|
||||
}
|
||||
else if (vage < 45)
|
||||
{
|
||||
msg = "大哥,你好能给我介绍个对象吗?";
|
||||
}
|
||||
else if (vage < 55)
|
||||
{
|
||||
msg = "大叔,你家邻居有小妹妹介绍吗?";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "还不退休?别写代码了!";
|
||||
}
|
||||
return $"{vname}:你好,我是SoEasy,{msg}";
|
||||
}
|
||||
|
||||
[AnnoInfo(Desc = "两个整数相加等于几?我来帮你算")]
|
||||
public int Add([AnnoInfo(Desc = "整数X")] int x, [AnnoInfo(Desc = "整数Y")] int y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
[AnnoInfo(Desc = "买个商品吧,双十一马上就来了")]
|
||||
public ProductDto BuyProduct([AnnoInfo(Desc = "商品名称")] string productName, [AnnoInfo(Desc = "商品数量")] int number)
|
||||
{
|
||||
double price = new Random().Next(2, 90);
|
||||
return new ProductDto() { Name=productName,Price=price ,Number=number, CountryOfOrigin="中国台湾"};
|
||||
}
|
||||
}
|
||||
}
|
||||
34
samples/Packages/Anno.Plugs.SoEasyService/SoEasyBootStrap.cs
Normal file
34
samples/Packages/Anno.Plugs.SoEasyService/SoEasyBootStrap.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Anno.EngineData;
|
||||
using System;
|
||||
|
||||
namespace Anno.Plugs.SoEasyService
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件启动引导器
|
||||
/// DependsOn 依赖的类型程序集自动注入DI容器
|
||||
/// </summary>
|
||||
[DependsOn(
|
||||
//typeof(Domain.Bootstrap)
|
||||
//, typeof(QueryServices.Bootstrap)
|
||||
//, typeof(Repository.Bootstrap)
|
||||
//, typeof(Command.Handler.Bootstrap
|
||||
)]
|
||||
public class SoEasyBootStrap : IPlugsConfigurationBootstrap
|
||||
{
|
||||
/// <summary>
|
||||
/// Service 依赖注入构建之后调用
|
||||
/// </summary>
|
||||
public void ConfigurationBootstrap()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
/// <summary>
|
||||
/// Service 依赖注入构建之前调用
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
public void PreConfigurationBootstrap()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Anno.EngineData" Version="1.0.2.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Anno.EngineData\Anno.EngineData.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
40
samples/Packages/Anno.Plugs.TraceService/TraceModule.cs
Normal file
40
samples/Packages/Anno.Plugs.TraceService/TraceModule.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Anno.EngineData;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Anno.Const.Attribute;
|
||||
|
||||
namespace Anno.Plugs.TraceService
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class TraceModule : BaseModule
|
||||
{
|
||||
|
||||
public TraceModule()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 批量接收追踪信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AnnoInfo(Desc = "持久化链路信息")]
|
||||
public ActionResult TraceBatch()
|
||||
{
|
||||
/*
|
||||
* 调用链路信息写入磁盘
|
||||
* 开发人员可以根据需要选择写入关系数据库、ES、MongoDB等等
|
||||
*/
|
||||
Log.Log.Info(RequestString("traces"));
|
||||
return new ActionResult(true, null, null, null);
|
||||
}
|
||||
|
||||
#region Module 初始化
|
||||
public override bool Init(Dictionary<string, string> input)
|
||||
{
|
||||
base.Init(input);
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
7
samples/Packages/HelloWorldDto/HelloWorldDto.csproj
Normal file
7
samples/Packages/HelloWorldDto/HelloWorldDto.csproj
Normal file
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
13
samples/Packages/HelloWorldDto/ProductDto.cs
Normal file
13
samples/Packages/HelloWorldDto/ProductDto.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace HelloWorldDto
|
||||
{
|
||||
public class ProductDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Number { get; set; }
|
||||
public double Price { get; set; }
|
||||
public double Amount { get { return Price * Number; } }
|
||||
public string CountryOfOrigin { get; set; }
|
||||
}
|
||||
}
|
||||
9
samples/Thrift/AnnoCenter/Anno.config
Normal file
9
samples/Thrift/AnnoCenter/Anno.config
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<!--#lbs 配置-->
|
||||
<Port>6660</Port>
|
||||
<TimeOut>120000</TimeOut>
|
||||
<Servers>
|
||||
|
||||
</Servers>
|
||||
</configuration>
|
||||
1
samples/Thrift/AnnoCenter/AnnoCenter.bat
Normal file
1
samples/Thrift/AnnoCenter/AnnoCenter.bat
Normal file
@@ -0,0 +1 @@
|
||||
dotnet AnnoCenter.dll
|
||||
33
samples/Thrift/AnnoCenter/AnnoCenter.csproj
Normal file
33
samples/Thrift/AnnoCenter/AnnoCenter.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>$(DeveloperBuildCoreTfms)</TargetFramework>
|
||||
<Authors>杜燕明</Authors>
|
||||
<Company>杜燕明</Company>
|
||||
<Version>1.0.0.1</Version>
|
||||
<!--win-x86;win-x64;linux-x64;osx-x64-->
|
||||
<!--<RuntimeIdentifiers>win-x86</RuntimeIdentifiers>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Core\Anno.Rpc.Center\Anno.Rpc.Center.csproj" />
|
||||
<RuntimeHostConfigurationOption Include="System.Globalization.Invariant" Value="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="AnnoCenter.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Anno.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="stop.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="start.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
18
samples/Thrift/AnnoCenter/Program.cs
Normal file
18
samples/Thrift/AnnoCenter/Program.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AnnoCenter
|
||||
{
|
||||
using Anno.Rpc.Center;
|
||||
static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.Title = "AnnoCenter";
|
||||
Bootstrap.StartUp(args);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
samples/Thrift/AnnoCenter/ddcenter.sh
Normal file
11
samples/Thrift/AnnoCenter/ddcenter.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
if [ $1 == "start" ];then
|
||||
nohup dotnet AnnoCenter.dll 2>&1 &
|
||||
echo "$!" > pid
|
||||
echo "start ok!"
|
||||
elif [ $1 == "stop" ];then
|
||||
kill `cat pid`
|
||||
echo "stop ok!"
|
||||
else
|
||||
echo "Please make sure the position variable is start or stop."
|
||||
fi
|
||||
53
samples/Thrift/AnnoService/Anno.config
Normal file
53
samples/Thrift/AnnoService/Anno.config
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<!--0,0 第一位是 工作站,第二位数据中心
|
||||
(所有的 AnnoService 的 两位数不能重复例如不能存在【1,2】【1,2】)
|
||||
可以存在【1,2】【2,1】
|
||||
-->
|
||||
<IdWorker>0,0</IdWorker>
|
||||
<!--App名称-->
|
||||
<AppName>App001</AppName>
|
||||
<!--监听端口-->
|
||||
<Port>6659</Port>
|
||||
<!--权重-->
|
||||
<Weight>1</Weight>
|
||||
<!--功能 非Anno.Plugs 加入方式-->
|
||||
<FuncName></FuncName>
|
||||
<!--忽略的功能 Trace,Logic-->
|
||||
<IgnoreFuncName></IgnoreFuncName>
|
||||
<!--超时时间毫秒-->
|
||||
<TimeOut>20000</TimeOut>
|
||||
<!--注册到的目标-->
|
||||
<Ts Ip="127.0.0.1" Port="6660"/>
|
||||
<IocDll>
|
||||
<!-- IOC 仓储--><!--
|
||||
<Assembly>Anno.Repository</Assembly>
|
||||
--><!-- 领域--><!--
|
||||
<Assembly>Anno.Domain</Assembly>
|
||||
--><!-- 查询服务--><!--
|
||||
<Assembly>Anno.QueryServices</Assembly>
|
||||
--><!--事件Handler--><!--
|
||||
<Assembly>Anno.Command.Handler</Assembly>-->
|
||||
</IocDll>
|
||||
<appSettings>
|
||||
<!-- 数据库连接字符串 Mysql-->
|
||||
<add key="ConnStr" value="server=127.0.0.1;database=bif;uid=bif;pwd=123456;SslMode=None;"/>
|
||||
<!--重置默认密码-->
|
||||
<add key="DefaultPwd" value="123456"/>
|
||||
<!--
|
||||
redisConn Redis 连接字符串
|
||||
redisPrefix Key 前缀
|
||||
redisExpiryDate Key 有效期 单位(分钟)
|
||||
redisSwitch 是否开启数据库 false 不开启
|
||||
-->
|
||||
<add key="redisConn" value="127.0.0.1:6379,abortConnect=false,allowAdmin =true,keepAlive=180"/>
|
||||
<add key="redisPrefix" value="Anno:"/>
|
||||
<add key="redisExpiryDate" value="20"/>
|
||||
<add key="redisSwitch" value="false"/>
|
||||
<!--MongoDB 配置-->
|
||||
<add key="MongoConn" value="mongodb://192.168.1.2"/>
|
||||
<add key="MongodName" value="bif"/>
|
||||
</appSettings>
|
||||
<!--RabbitMQ 配置-->
|
||||
<RabbitMQ key="RabbitMQ" HostName="10.10.10.39" UserName="bsc" Password="bsc$15" VirtualHost="test" Port="5672"/>
|
||||
</configuration>
|
||||
1
samples/Thrift/AnnoService/AnnoService.bat
Normal file
1
samples/Thrift/AnnoService/AnnoService.bat
Normal file
@@ -0,0 +1 @@
|
||||
dotnet AnnoService.dll
|
||||
39
samples/Thrift/AnnoService/AnnoService.csproj
Normal file
39
samples/Thrift/AnnoService/AnnoService.csproj
Normal file
@@ -0,0 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win10-x64;</RuntimeIdentifiers>
|
||||
<TargetFrameworks>$(DeveloperBuildCoreTfms);net461</TargetFrameworks>
|
||||
<Authors>杜燕明</Authors>
|
||||
<Company>杜燕明</Company>
|
||||
<Version>1.0.0.1</Version>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<RuntimeHostConfigurationOption Include="System.Globalization.Invariant" Value="true" />
|
||||
<None Update="Packages\Plugs插件使用说明.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="start.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="AnnoService.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Anno.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="stop.sh">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Core\Anno.Rpc.Server\Anno.Rpc.Server.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.DLockService\Anno.Plugs.DLockService.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.HelloWorldService\Anno.Plugs.HelloWorldService.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.SoEasyService\Anno.Plugs.SoEasyService.csproj" />
|
||||
<ProjectReference Include="..\..\Packages\Anno.Plugs.TraceService\Anno.Plugs.TraceService.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
Plugs插件使用说明
|
||||
|
||||
1、Plugs插件使用说明
|
||||
1.1 插件存放在宿主程序的根目录下的 Packages 文件夹下面。
|
||||
1.2 插件例如【dym.Plugs.SerialRule】序列生成服务 必须以目录形成存在
|
||||
1.3 插件目录结构如下
|
||||
dym.Plugs.SerialRule
|
||||
|
|
||||
dym.Plugs.SerialRuleService.dll
|
||||
1.4 宿主程序会加载插件【XXX】目录【dym.Plugs.XXX】下面的入口文件【dym.Plugs.XXXService.dll】
|
||||
10
samples/Thrift/AnnoService/Packages/Plugs插件使用说明.txt
Normal file
10
samples/Thrift/AnnoService/Packages/Plugs插件使用说明.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Plugs插件使用说明
|
||||
|
||||
1、Plugs插件使用说明
|
||||
1.1 插件存放在宿主程序的根目录下的 Packages 文件夹下面。
|
||||
1.2 插件例如【dym.Plugs.SerialRule】序列生成服务 必须以目录形成存在
|
||||
1.3 插件目录结构如下
|
||||
dym.Plugs.SerialRule
|
||||
|
|
||||
dym.Plugs.SerialRuleService.dll
|
||||
1.4 宿主程序会加载插件【XXX】目录【dym.Plugs.XXX】下面的入口文件【dym.Plugs.XXXService.dll】
|
||||
113
samples/Thrift/AnnoService/Program.cs
Normal file
113
samples/Thrift/AnnoService/Program.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Anno.Const.Attribute;
|
||||
using Anno.Loader;
|
||||
using Anno.Log;
|
||||
using Autofac;
|
||||
|
||||
namespace AnnoService
|
||||
{
|
||||
using Anno.EngineData;
|
||||
using Anno.Rpc.Server;
|
||||
using System.Collections.Generic;
|
||||
using Anno.Rpc.Storage;
|
||||
static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Contains("-help"))
|
||||
{
|
||||
Log.ConsoleWriteLine(@"
|
||||
启动参数:
|
||||
-p 6659 设置启动端口
|
||||
-xt 200 设置服务最大线程数
|
||||
-t 20000 设置超时时间(单位毫秒)
|
||||
-w 1 设置权重
|
||||
-h 192.168.0.2 设置服务在注册中心的地址
|
||||
-tr false 设置调用链追踪是否启用");
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* 启动默认DI库为 Autofac 可以切换为微软自带的DI库 DependencyInjection
|
||||
*/
|
||||
Bootstrap.StartUp(args, () =>//服务配置文件读取完成后回调(服务未启动)
|
||||
{
|
||||
//Anno.Const.SettingService.TraceOnOff = true;
|
||||
|
||||
/*
|
||||
* 功能插件选择是Thrift还是 Grpc
|
||||
* Install-Package Anno.Rpc.Client -Version 1.0.2.6 Thrift
|
||||
* Install-Package Anno.Rpc.ServerGrpc -Version 1.0.1.5 Grpc
|
||||
* 此处为 Thrift
|
||||
*/
|
||||
var autofac = IocLoader.GetAutoFacContainerBuilder();
|
||||
autofac.RegisterType(typeof(RpcConnectorImpl)).As(typeof(IRpcConnector)).SingleInstance();
|
||||
}
|
||||
, () =>//服务启动后的回调方法
|
||||
{
|
||||
/**
|
||||
* 服务Api文档写入注册中心
|
||||
*/
|
||||
ApiDoc();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///服务启动后将服务Api文档写入注册中心
|
||||
///
|
||||
///增加自己的服务的时候只用复制下面的代码就可以不用做修改
|
||||
/// </summary>
|
||||
static void ApiDoc()
|
||||
{
|
||||
List<AnnoData> routings = new List<AnnoData>();
|
||||
foreach (var item in Anno.EngineData.Routing.Routing.Router)
|
||||
{
|
||||
if (item.Value.RoutMethod.Name == "get_ActionResult")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var parameters = item.Value.RoutMethod.GetParameters().ToList().Select(it =>
|
||||
{
|
||||
var parameter = new ParametersValue
|
||||
{ Name = it.Name, Position = it.Position, ParameterType = it.ParameterType.FullName };
|
||||
var pa = it.GetCustomAttributes<AnnoInfoAttribute>().ToList();
|
||||
if (pa.Any())
|
||||
{
|
||||
parameter.Desc = pa.First().Desc;
|
||||
}
|
||||
return parameter;
|
||||
}).ToList();
|
||||
string methodDesc = String.Empty;
|
||||
var mAnnoInfoAttributes = item.Value.RoutMethod.GetCustomAttributes<AnnoInfoAttribute>().ToList();
|
||||
if (mAnnoInfoAttributes.Count > 0)
|
||||
{
|
||||
methodDesc = mAnnoInfoAttributes.First().Desc;
|
||||
}
|
||||
routings.Add(new AnnoData()
|
||||
{
|
||||
App = Anno.Const.SettingService.AppName,
|
||||
Id = $"{Anno.Const.SettingService.AppName}:{item.Key}",
|
||||
Value = Newtonsoft.Json.JsonConvert.SerializeObject(new DataValue { Desc = methodDesc, Name = item.Value.RoutMethod.Name, Parameters = parameters })
|
||||
});
|
||||
}
|
||||
Dictionary<string, string> input = new Dictionary<string, string>();
|
||||
input.Add(CONST.Opt, CONST.DeleteByApp);
|
||||
input.Add(CONST.App, Anno.Const.SettingService.AppName);
|
||||
var del = Newtonsoft.Json.JsonConvert.DeserializeObject<AnnoDataResult>(StorageEngine.Invoke(input));
|
||||
if (del.Status == false)
|
||||
{
|
||||
Log.Error(del);
|
||||
}
|
||||
input.Clear();
|
||||
input.Add(CONST.Opt, CONST.UpsertBatch);
|
||||
input.Add(CONST.Data, Newtonsoft.Json.JsonConvert.SerializeObject(routings));
|
||||
var rlt = Newtonsoft.Json.JsonConvert.DeserializeObject<AnnoDataResult>(StorageEngine.Invoke(input));
|
||||
if (rlt.Status == false)
|
||||
{
|
||||
Log.Error(rlt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
samples/Thrift/AnnoService/ddservice.sh
Normal file
11
samples/Thrift/AnnoService/ddservice.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
if [ $1 == "start" ];then
|
||||
nohup dotnet AnnoService.dll 2>&1 &
|
||||
echo "$!" > pid
|
||||
echo "start ok!"
|
||||
elif [ $1 == "stop" ];then
|
||||
kill `cat pid`
|
||||
echo "stop ok!"
|
||||
else
|
||||
echo "Please make sure the position variable is start or stop."
|
||||
fi
|
||||
3
samples/Thrift/annoCenter.bat
Normal file
3
samples/Thrift/annoCenter.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoCenter/bin/Debug/netcoreapp3.1
|
||||
dotnet AnnoCenter.dll
|
||||
3
samples/Thrift/annoCenterRelease.bat
Normal file
3
samples/Thrift/annoCenterRelease.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoCenter/bin/Release/netcoreapp3.1
|
||||
dotnet AnnoCenter.dll
|
||||
3
samples/Thrift/annoService.bat
Normal file
3
samples/Thrift/annoService.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoService/bin/Debug/netcoreapp3.1
|
||||
dotnet AnnoService.dll
|
||||
3
samples/Thrift/annoServiceRelease.bat
Normal file
3
samples/Thrift/annoServiceRelease.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
cd %cd%
|
||||
cd ./AnnoService/bin/Release/netcoreapp3.1
|
||||
dotnet AnnoService.dll
|
||||
15
src/Anno.Const/Anno.Const.csproj
Normal file
15
src/Anno.Const/Anno.Const.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTfms);net461</TargetFrameworks>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>Du yanming</Authors>
|
||||
<Company>Du yanming</Company>
|
||||
<Product>Anno 分布式开发框架</Product>
|
||||
<Description>分布式开发框架 配置</Description>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<Version>$(Version)</Version>
|
||||
<PackageProjectUrl>https://github.com/duyanming/Viper</PackageProjectUrl>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
21
src/Anno.Const/AppSettings.cs
Normal file
21
src/Anno.Const/AppSettings.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace Anno.Const
|
||||
{
|
||||
public static class AppSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库连接字符串
|
||||
/// </summary>
|
||||
public static String ConnStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户重置密码的时候的默认密码
|
||||
/// </summary>
|
||||
public static String DefaultPwd { get; set; } = "Anno";
|
||||
/// <summary>
|
||||
/// Ioc插件DLL列表
|
||||
/// </summary>
|
||||
public static List<string> IocDll { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
||||
23
src/Anno.Const/Attribute/AnnoInfoAttribute.cs
Normal file
23
src/Anno.Const/Attribute/AnnoInfoAttribute.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
/******************************************************
|
||||
Writer:Du YanMing
|
||||
Mail:dym880@163.com
|
||||
Create Date:2020/7/8 18:45:34
|
||||
Functional description: AnnoInfoAttribute
|
||||
******************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Const.Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 描述注解
|
||||
/// </summary>
|
||||
public class AnnoInfoAttribute : System.Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public String Desc { get; set; }
|
||||
}
|
||||
}
|
||||
25
src/Anno.Const/Enum/Eng.cs
Normal file
25
src/Anno.Const/Enum/Eng.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace Anno.Const.Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// Engine 常量
|
||||
/// </summary>
|
||||
public static class Eng
|
||||
{
|
||||
/// <summary>
|
||||
/// 命名空间
|
||||
/// </summary>
|
||||
public const string NAMESPACE = "channel";
|
||||
/// <summary>
|
||||
/// 类
|
||||
/// </summary>
|
||||
public const string CLASS = "router";
|
||||
/// <summary>
|
||||
/// 方法
|
||||
/// </summary>
|
||||
public const string METHOD = "method";
|
||||
/// <summary>
|
||||
/// 免登陆
|
||||
/// </summary>
|
||||
public const string PASS = "_Login";
|
||||
}
|
||||
}
|
||||
18
src/Anno.Const/MongoConfigure.cs
Normal file
18
src/Anno.Const/MongoConfigure.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Const
|
||||
{
|
||||
public static class MongoConfigure
|
||||
{
|
||||
/// <summary>
|
||||
/// 链接字符串
|
||||
/// </summary>
|
||||
public static string connectionString { get; set; }
|
||||
/// <summary>
|
||||
/// 数据库
|
||||
/// </summary>
|
||||
public static string database { get; set; }
|
||||
}
|
||||
}
|
||||
62
src/Anno.Const/RedisConfigure.cs
Normal file
62
src/Anno.Const/RedisConfigure.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.Const
|
||||
{
|
||||
/// <summary>
|
||||
/// Redis 配置
|
||||
/// </summary>
|
||||
public class RedisConfigure
|
||||
{
|
||||
private static readonly object _locker = new Object();
|
||||
private static RedisConfigure redisConfigure = null;
|
||||
/// <summary>
|
||||
/// 连接字符串 默认:127.0.0.1:6379,abortConnect=false,allowAdmin =true,keepAlive=180
|
||||
/// </summary>
|
||||
public string Conn { get; set; } = "127.0.0.1:6379,abortConnect=false,allowAdmin =true,keepAlive=180";
|
||||
/// <summary>
|
||||
/// Key前缀 默认:Anno:
|
||||
/// </summary>
|
||||
public string Prefix { get; set; } = "Anno:";
|
||||
|
||||
/// <summary>
|
||||
/// 有效期 默认:20分钟
|
||||
/// </summary>
|
||||
public TimeSpan ExpiryDate { get; set; } = TimeSpan.FromMinutes(20);
|
||||
/// <summary>
|
||||
/// 开关 默认 关 false
|
||||
/// </summary>
|
||||
public Boolean Switch { get; set; } = false;
|
||||
private RedisConfigure() { }
|
||||
|
||||
public static RedisConfigure Default()
|
||||
{
|
||||
if (redisConfigure == null)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (redisConfigure == null)
|
||||
{
|
||||
redisConfigure = new RedisConfigure();
|
||||
}
|
||||
}
|
||||
}
|
||||
return redisConfigure;
|
||||
}
|
||||
/// <summary>
|
||||
/// Redis 配置
|
||||
/// </summary>
|
||||
/// <param name="Conn">数据库连接字符串</param>
|
||||
/// <param name="Prefix">前缀</param>
|
||||
/// <param name="ExpiryDate">有效期</param>
|
||||
/// <param name="Switch">开关</param>
|
||||
public void SetDefault(string Conn, string Prefix, TimeSpan ExpiryDate, Boolean Switch)
|
||||
{
|
||||
this.Conn = Conn;
|
||||
this.Prefix = Prefix;
|
||||
this.ExpiryDate = ExpiryDate;
|
||||
this.Switch = Switch;
|
||||
}
|
||||
}
|
||||
}
|
||||
462
src/Anno.Const/SettingService.cs
Normal file
462
src/Anno.Const/SettingService.cs
Normal file
@@ -0,0 +1,462 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace Anno.Const
|
||||
{
|
||||
public static class SettingService
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务名称
|
||||
/// </summary>
|
||||
public static string AppName { get; set; } = "AnnoService";
|
||||
/// <summary>
|
||||
/// 服务端最大工作线程数量
|
||||
/// </summary>
|
||||
public static int MaxThreads { get; set; } = 200;
|
||||
|
||||
/// <summary>
|
||||
/// 本机信息
|
||||
/// </summary>
|
||||
public static Target Local { get; set; } = new Target();
|
||||
/// <summary>
|
||||
/// 权重
|
||||
/// </summary>
|
||||
public static int Weight { get; set; }
|
||||
/// <summary>
|
||||
/// 功能
|
||||
/// </summary>
|
||||
public static string FuncName { get; set; }
|
||||
/// <summary>
|
||||
/// 忽略的功能
|
||||
/// </summary>
|
||||
public static List<string> IgnoreFuncNames { get; set; } = new List<string>();
|
||||
/// <summary>
|
||||
/// 服务超时时间 单位毫秒
|
||||
/// </summary>
|
||||
public static long TimeOut { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 调用追踪开关
|
||||
/// </summary>
|
||||
public static bool TraceOnOff { get; set; } = true;
|
||||
/// <summary>
|
||||
/// 服务注册目标
|
||||
/// </summary>
|
||||
public static List<Target> Ts { get; set; } = new List<Target>();
|
||||
|
||||
/// <summary>
|
||||
/// 日志配置文件路径 Log4net
|
||||
/// </summary>
|
||||
public static string LogCfg;
|
||||
|
||||
/// <summary>
|
||||
/// 工作站
|
||||
/// </summary>
|
||||
public static long WorkerId { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// 数据中心
|
||||
/// </summary>
|
||||
public static long DatacenterId { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// 通过Anno.config 初始化AppSettings
|
||||
/// </summary>
|
||||
/// <param name="doc"></param>
|
||||
private static void InitConstAppSettings(XmlDocument doc)
|
||||
{
|
||||
XmlNodeList assembly = doc.SelectNodes("//IocDll/Assembly");
|
||||
foreach (XmlNode n in assembly)
|
||||
{
|
||||
AppSettings.IocDll.Add(n.InnerText);
|
||||
}
|
||||
AppSettings.ConnStr = AppSetting("ConnStr");
|
||||
AppSettings.DefaultPwd = AppSetting("DefaultPwd");
|
||||
//Redis 配置
|
||||
RedisConfigure.Default().Conn = AppSetting("redisConn");
|
||||
RedisConfigure.Default().Prefix = AppSetting("redisPrefix");
|
||||
if (double.TryParse(AppSetting("redisExpiryDate"), out double redisExpiryDate))
|
||||
{
|
||||
|
||||
RedisConfigure.Default().ExpiryDate = TimeSpan.FromMinutes(redisExpiryDate);
|
||||
}
|
||||
if (bool.TryParse(AppSetting("redisSwitch"), out bool redisSwitch))
|
||||
{
|
||||
RedisConfigure.Default().Switch = redisSwitch;
|
||||
}
|
||||
|
||||
//MongoDb 配置
|
||||
MongoConfigure.connectionString = AppSetting("MongoConn");
|
||||
MongoConfigure.database = AppSetting("MongodName");
|
||||
|
||||
//Log4net 配置
|
||||
LogCfg = Path.Combine(Directory.GetCurrentDirectory(), "log4net.config");
|
||||
}
|
||||
/// <summary>
|
||||
/// AppSetting //appSettings/add[@key='{key}']
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
private static string AppSetting(string key)
|
||||
{
|
||||
XmlDocument doc = GetXmlDocument();
|
||||
XmlNode appset = doc.SelectSingleNode($"//appSettings/add[@key='{key}']");
|
||||
return appset == null ? string.Empty : appset.Attributes["value"].Value;
|
||||
}
|
||||
/// <summary>
|
||||
///NodeText
|
||||
///SelectSingleNode("//AppName")?.InnerText
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
private static string NodeText(string key)
|
||||
{
|
||||
XmlDocument doc = GetXmlDocument();
|
||||
string appset = doc.SelectSingleNode($"//{key}")?.InnerText;
|
||||
return appset ?? string.Empty;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取文档
|
||||
/// </summary>
|
||||
/// <param name="docName">默认 Anno.config</param>
|
||||
/// <returns></returns>
|
||||
private static XmlDocument GetXmlDocument(string docName = "Anno.config")
|
||||
{
|
||||
string xmlPath = Path.Combine(Directory.GetCurrentDirectory(), docName);
|
||||
XmlDocument xmlDoc = new XmlDocument();
|
||||
if (File.Exists(xmlPath))
|
||||
{
|
||||
xmlDoc.Load(xmlPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder xmlText = new StringBuilder();
|
||||
#region AnnoService Anno.config
|
||||
|
||||
xmlText.Append(@"<?xml version='1.0' encoding='utf-8' ?>
|
||||
<configuration>
|
||||
<!--0,0 第一位是 工作站,第二位数据中心
|
||||
(所有的 AnnoService 的 两位数不能重复例如不能存在【1,2】【1,2】)
|
||||
可以存在【1,2】【2,1】
|
||||
-->
|
||||
<IdWorker>0,0</IdWorker>
|
||||
<!--App名称-->
|
||||
<AppName>App001</AppName>
|
||||
<!--监听端口-->
|
||||
<Port>6659</Port>
|
||||
<!--权重-->
|
||||
<Weight>1</Weight>
|
||||
<!--功能 <FuncName>Anno.Plugs.LogicService,Anno.Plugs.TraceService</FuncName> -->
|
||||
<FuncName></FuncName>
|
||||
<!--忽略的功能-->
|
||||
<IgnoreFuncName></IgnoreFuncName>
|
||||
<!--超时时间毫秒-->
|
||||
<TimeOut>2000</TimeOut>
|
||||
<!--注册到的目标-->
|
||||
<Ts Ip='127.0.0.1' Port='6660'/>
|
||||
<IocDll>
|
||||
<!-- IOC 仓储-->
|
||||
<!-- <Assembly>Anno.Repository</Assembly> -->
|
||||
<!-- 领域-->
|
||||
<!-- <Assembly>Anno.Domain</Assembly> -->
|
||||
<!-- 查询服务-->
|
||||
<!-- <Assembly>Anno.QueryServices</Assembly> -->
|
||||
<!--事件Handler-->
|
||||
<!--<Assembly>Anno.Command.Handler</Assembly>-->
|
||||
</IocDll>
|
||||
<appSettings>
|
||||
<!-- 数据库连接字符串 Mysql-->
|
||||
<add key='ConnStr' value='server=127.0.0.1;database=bif;uid=bif;pwd=123456;SslMode=None;'/>
|
||||
<!--重置默认密码-->
|
||||
<add key='DefaultPwd' value='123456'/>
|
||||
<!--
|
||||
redisConn Redis 连接字符串
|
||||
redisPrefix Key 前缀
|
||||
redisExpiryDate Key 有效期 单位(分钟)
|
||||
redisSwitch 是否开启数据库 false 不开启
|
||||
-->
|
||||
<add key='redisConn' value='127.0.0.1:6379,abortConnect=false,allowAdmin =true,keepAlive=180'/>
|
||||
<add key='redisPrefix' value='Anno:'/>
|
||||
<add key='redisExpiryDate' value='20'/>
|
||||
<add key='redisSwitch' value='false'/>
|
||||
<!--MongoDB 配置-->
|
||||
<add key='MongoConn' value='mongodb://192.168.1.2'/>
|
||||
<add key='MongodName' value='bif'/>
|
||||
</appSettings>
|
||||
<!--RabbitMQ 配置-->
|
||||
<RabbitMQ key='RabbitMQ' HostName='192.168.100.173' UserName='dev' Password='dev' VirtualHost='dev' Port='5672'/>
|
||||
</configuration>
|
||||
");
|
||||
#endregion
|
||||
xmlDoc.LoadXml(xmlText.ToString());
|
||||
xmlDoc.Save(xmlPath);
|
||||
}
|
||||
return xmlDoc;
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化配置Anno.config
|
||||
/// </summary>
|
||||
public static void InitConfig()
|
||||
{
|
||||
#region 配置初始化
|
||||
XmlDocument xml = GetXmlDocument();
|
||||
XmlNode local = xml.SelectSingleNode("//Port");
|
||||
Local.Port = Convert.ToInt32(NodeText("Port"));
|
||||
//Local.IpAddress = local.Attributes["Ip"].Value;
|
||||
Weight = Convert.ToInt32(NodeText("Weight"));
|
||||
AppName = NodeText("AppName");
|
||||
FuncName = NodeText("FuncName");
|
||||
if (long.TryParse(NodeText("TimeOut"), out long timeOut))
|
||||
{
|
||||
TimeOut = timeOut;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeOut = 10000;
|
||||
}
|
||||
XmlNodeList _Ts = xml.SelectNodes("//Ts");
|
||||
#region 需要忽略的 插件
|
||||
var ignoreFunc = NodeText("IgnoreFuncName");
|
||||
ignoreFunc.Split(',').ToList().ForEach(item =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item))
|
||||
{
|
||||
IgnoreFuncNames.Add(item.ToUpper());
|
||||
}
|
||||
});
|
||||
#endregion
|
||||
foreach (XmlNode ts in _Ts)
|
||||
{
|
||||
Target target = new Target
|
||||
{
|
||||
IpAddress = ts.Attributes["Ip"].Value,
|
||||
Port = Convert.ToInt32(ts.Attributes["Port"].Value)
|
||||
};
|
||||
Ts.Add(target);
|
||||
}
|
||||
//通过Anno.config 初始化AppSettings
|
||||
InitConstAppSettings(xml);
|
||||
//根据 SettingService.FuncName 加载服务集合
|
||||
Assemblys.InitAssembly();
|
||||
Assemblys.AddPlugsAssembly();
|
||||
|
||||
CustomConfiguration.InitConst(xml);
|
||||
#endregion
|
||||
|
||||
#region 初始化 ID生成器
|
||||
|
||||
var idWorker = NodeText("IdWorker");
|
||||
if (!string.IsNullOrWhiteSpace(idWorker))
|
||||
{
|
||||
var wd = idWorker.Split(',');
|
||||
if (wd.Length == 2)
|
||||
{
|
||||
long.TryParse(wd[0], out long worker);
|
||||
long.TryParse(wd[1], out long datacenter);
|
||||
WorkerId = worker;
|
||||
DatacenterId = datacenter;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 目标信息
|
||||
/// </summary>
|
||||
public class Target
|
||||
{
|
||||
/// <summary>
|
||||
/// IP地址
|
||||
/// </summary>
|
||||
public string IpAddress { get; set; }
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务集
|
||||
/// </summary>
|
||||
public static class Assemblys
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务集合
|
||||
/// </summary>
|
||||
public static readonly Dictionary<string, Assembly> Dic = new Dictionary<string, Assembly>();
|
||||
/// <summary>
|
||||
/// Ioc模块DLL列表
|
||||
/// </summary>
|
||||
public static List<Assembly> DependedTypes { get; set; } = new List<Assembly>();
|
||||
/// <summary>
|
||||
/// 根据 SettingService.FuncName 加载服务集合
|
||||
/// </summary>
|
||||
public static void InitAssembly()
|
||||
{
|
||||
SettingService.FuncName?.Split(',').Where(f => !string.IsNullOrWhiteSpace(f)).ToList().ForEach(f =>
|
||||
{
|
||||
string dllPath = Path.Combine(Directory.GetCurrentDirectory(), $"{f}.dll");
|
||||
Assembly assembly = null;
|
||||
if (File.Exists(dllPath))
|
||||
{
|
||||
assembly = Assembly.UnsafeLoadFrom(dllPath); //装载组件
|
||||
}
|
||||
#if DEBUG
|
||||
else if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", Environment.CommandLine.Split(Path.DirectorySeparatorChar)[Environment.CommandLine.Split(Path.DirectorySeparatorChar).Length - 2], $"{f}.dll")))
|
||||
{
|
||||
dllPath = Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", Environment.CommandLine.Split(Path.DirectorySeparatorChar)[Environment.CommandLine.Split(Path.DirectorySeparatorChar).Length - 2],
|
||||
$"{f}.dll");
|
||||
assembly = Assembly.UnsafeLoadFrom(dllPath); //装载组件
|
||||
}
|
||||
#endif
|
||||
else if (!string.IsNullOrWhiteSpace(f))
|
||||
{
|
||||
Console.WriteLine($"{f} 服务没有找到!检查目录【{Directory.GetCurrentDirectory()}】下文件是否存在!");
|
||||
}
|
||||
if (assembly != null && !Dic.ContainsKey(f))
|
||||
{
|
||||
Dic.Add(f, assembly);
|
||||
|
||||
if (AppSettings.IocDll.All(plug => plug != f))
|
||||
{
|
||||
AppSettings.IocDll.Add(f);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加扩展Assembly
|
||||
/// </summary>
|
||||
public static void AddPlugsAssembly()
|
||||
{
|
||||
#region 根目录 插件
|
||||
var plugs = new DirectoryInfo(Directory.GetCurrentDirectory()).GetFiles()
|
||||
.Where(f => f.Name.StartsWith("Anno.Plugs.") && f.Name.EndsWith("Service.dll"))
|
||||
.ToList();
|
||||
for (int i = 0; i < plugs.Count; i++)
|
||||
{
|
||||
var plugNameService = plugs[i].Name.Remove(plugs[i].Name.Length - 4, 4);
|
||||
if (SettingService.IgnoreFuncNames.Exists(ig => plugNameService.ToUpper().Contains(ig)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
var assembly =
|
||||
Assembly.UnsafeLoadFrom(plugs[i].FullName); //装载组件
|
||||
if (!Dic.ContainsKey(plugNameService))
|
||||
{
|
||||
Dic.Add($"{plugNameService}", assembly);
|
||||
if (!string.IsNullOrEmpty(SettingService.FuncName))
|
||||
{
|
||||
SettingService.FuncName += ",";
|
||||
}
|
||||
SettingService.FuncName += plugNameService;
|
||||
}
|
||||
if (AppSettings.IocDll.All(plug => plug != plugNameService))
|
||||
{
|
||||
AppSettings.IocDll.Add(plugNameService);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"插件【{ plugNameService}】加载出错!");
|
||||
Console.WriteLine($"错误信息:");
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region Packages 目录 插件
|
||||
var basePath = Path.Combine(Directory.GetCurrentDirectory(), "Packages");
|
||||
if (Directory.Exists(basePath))
|
||||
{
|
||||
foreach (DirectoryInfo plugInfo in new DirectoryInfo(basePath).GetDirectories().Where(dir => dir.Name.StartsWith("Anno.Plugs.")))
|
||||
{
|
||||
if (SettingService.IgnoreFuncNames.Exists(ig => plugInfo.Name.ToUpper().Contains(ig)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
var plugName = plugInfo.Name; //$"Anno.Plugs.SerialRule";
|
||||
var plugNameService = $"{plugName}Service";
|
||||
var plugsPath = Path.Combine(basePath, plugName, $"{plugNameService}.dll");
|
||||
if (File.Exists(plugsPath))
|
||||
{
|
||||
var assembly =
|
||||
Assembly.UnsafeLoadFrom(plugsPath); //装载组件
|
||||
if (!Dic.ContainsKey(plugNameService))
|
||||
{
|
||||
Dic.Add($"{plugNameService}", assembly);
|
||||
if (!string.IsNullOrEmpty(SettingService.FuncName))
|
||||
{
|
||||
SettingService.FuncName += ",";
|
||||
}
|
||||
SettingService.FuncName += plugNameService;
|
||||
}
|
||||
if (AppSettings.IocDll.All(plug => plug != plugNameService))
|
||||
{
|
||||
AppSettings.IocDll.Add(plugNameService);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"插件【{ plugInfo.Name}】加载出错!");
|
||||
Console.WriteLine($"错误信息:");
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数
|
||||
/// </summary>
|
||||
public static class CustomConfiguration
|
||||
{
|
||||
private static readonly Dictionary<string, string> settings = new Dictionary<string, string>();
|
||||
/// <summary>
|
||||
/// 自定义参数
|
||||
/// //appSettings
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> Settings => settings;
|
||||
|
||||
public static void InitConst(XmlDocument doc)
|
||||
{
|
||||
XmlNode appSettings = doc.SelectSingleNode("//appSettings");
|
||||
if (appSettings == null || appSettings.ChildNodes.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (XmlNode node in appSettings.ChildNodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (node.Attributes != null)
|
||||
{
|
||||
string key = node.Attributes["key"].Value;
|
||||
if (!string.IsNullOrWhiteSpace(key) && settings.ContainsKey(key) == false)
|
||||
{
|
||||
string value = node.Attributes["value"].Value;
|
||||
settings.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/Anno.CronNET/Anno.CronNET.csproj
Normal file
14
src/Anno.CronNET/Anno.CronNET.csproj
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTfms);net461</TargetFrameworks>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>$(Version)</Version>
|
||||
<Description>分布式开发框架 定时任务管理器</Description>
|
||||
<Authors>Du yanming</Authors>
|
||||
<Company>Du yanming</Company>
|
||||
<Product>Anno 定时任务</Product>
|
||||
<PackageProjectUrl>https://github.com/duyanming/Viper</PackageProjectUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
133
src/Anno.CronNET/CronDaemon.cs
Normal file
133
src/Anno.CronNET/CronDaemon.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Timers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Anno.CronNET
|
||||
{
|
||||
public interface ICronDaemon
|
||||
{
|
||||
ICronJob AddJob(string schedule, ThreadStart action);
|
||||
bool RemoveJob(ICronJob job);
|
||||
void Start();
|
||||
void Stop();
|
||||
DaemonStatus Status { get; set; }
|
||||
}
|
||||
|
||||
public class CronDaemon : ICronDaemon
|
||||
{
|
||||
private readonly System.Timers.Timer _timer = new System.Timers.Timer(1000);
|
||||
private readonly List<ICronJob> _cronJobs = new List<ICronJob>();
|
||||
private DateTime _last = DateTime.Now;
|
||||
private static readonly object JobLock = new object();
|
||||
|
||||
|
||||
public CronDaemon()
|
||||
{
|
||||
_timer.AutoReset = true;
|
||||
_timer.Elapsed += timer_elapsed;
|
||||
}
|
||||
|
||||
public DaemonStatus Status { get; set; } = DaemonStatus.Stop;
|
||||
/// <summary>
|
||||
/// 添加任务
|
||||
/// </summary>
|
||||
/// <param name="schedule">调度例如:*/30 * * * * ? *</param>
|
||||
/// <param name="action">任务</param>
|
||||
/// <returns></returns>
|
||||
public ICronJob AddJob(string schedule, ThreadStart action)
|
||||
{
|
||||
var cj = new CronJob(schedule, action);
|
||||
lock (JobLock)
|
||||
{
|
||||
_cronJobs.Add(cj);
|
||||
}
|
||||
return cj;
|
||||
}
|
||||
/// <summary>
|
||||
/// 移除任务
|
||||
/// </summary>
|
||||
/// <param name="job">被移除任务</param>
|
||||
/// <returns></returns>
|
||||
public bool RemoveJob(ICronJob job)
|
||||
{
|
||||
lock (JobLock)
|
||||
{
|
||||
job.abort();
|
||||
return _cronJobs.Remove(job);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 移除任务
|
||||
/// </summary>
|
||||
/// <param name="jobId">被移除任务</param>
|
||||
/// <returns></returns>
|
||||
public bool RemoveJob(Guid jobId)
|
||||
{
|
||||
lock (JobLock)
|
||||
{
|
||||
var job = _cronJobs.Find(j => j.ID == jobId);
|
||||
if (job != null)
|
||||
{
|
||||
job.abort();
|
||||
_cronJobs.Remove(job);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 启动任务管理器
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
#region 确保执行时间是 每秒的中间时刻执行
|
||||
int millisecond = DateTime.Now.Millisecond;
|
||||
if (millisecond > 500)
|
||||
{
|
||||
millisecond = 1500 - millisecond;
|
||||
}
|
||||
else if (millisecond < 500)
|
||||
{
|
||||
millisecond = 500 - millisecond;
|
||||
}
|
||||
|
||||
if (millisecond != 500)
|
||||
{
|
||||
Thread.Sleep(millisecond);
|
||||
}
|
||||
#endregion
|
||||
_timer.Start();
|
||||
Status = DaemonStatus.Started;
|
||||
}
|
||||
/// <summary>
|
||||
/// 停止任务管理器
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
Status = DaemonStatus.Stop;
|
||||
_timer.Stop();
|
||||
//foreach (CronJob job in cron_jobs)
|
||||
// job.abort();
|
||||
}
|
||||
|
||||
private void timer_elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (DateTime.Now.Second != _last.Second)
|
||||
{
|
||||
_last = DateTime.Now;
|
||||
lock (JobLock)
|
||||
{
|
||||
foreach (ICronJob job in _cronJobs)
|
||||
job.execute(DateTime.Now);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum DaemonStatus
|
||||
{
|
||||
Started = 0,
|
||||
Stop
|
||||
}
|
||||
}
|
||||
54
src/Anno.CronNET/CronJob.cs
Normal file
54
src/Anno.CronNET/CronJob.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Anno.CronNET
|
||||
{
|
||||
public interface ICronJob
|
||||
{
|
||||
Guid ID { get; }
|
||||
void execute(DateTime date_time);
|
||||
void abort();
|
||||
}
|
||||
|
||||
public class CronJob : ICronJob
|
||||
{
|
||||
private Guid id = Guid.NewGuid();
|
||||
private readonly ICronSchedule _cron_schedule = new CronSchedule();
|
||||
private readonly ThreadStart _thread_start;
|
||||
private Thread _thread;
|
||||
|
||||
public CronJob(string schedule, ThreadStart thread_start)
|
||||
{
|
||||
_cron_schedule = new CronSchedule(schedule);
|
||||
_thread_start = thread_start;
|
||||
_thread = new Thread(thread_start);
|
||||
}
|
||||
|
||||
private object _lock = new object();
|
||||
|
||||
public Guid ID { get => this.id; }
|
||||
|
||||
public void execute(DateTime date_time)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_cron_schedule.isTime(date_time))
|
||||
return;
|
||||
|
||||
if (_thread.ThreadState == ThreadState.Running)
|
||||
return;
|
||||
|
||||
_thread = new Thread(_thread_start);
|
||||
_thread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void abort()
|
||||
{
|
||||
#if !NETSTANDARD
|
||||
_thread.Abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
218
src/Anno.CronNET/CronSchedule.cs
Normal file
218
src/Anno.CronNET/CronSchedule.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Anno.CronNET
|
||||
{
|
||||
public interface ICronSchedule
|
||||
{
|
||||
bool isValid(string expression);
|
||||
bool isTime(DateTime date_time);
|
||||
}
|
||||
|
||||
public class CronSchedule : ICronSchedule
|
||||
{
|
||||
#region Readonly Class Members
|
||||
|
||||
readonly static Regex divided_regex = new Regex(@"(\*/\d+)");
|
||||
readonly static Regex range_regex = new Regex(@"(\d+\-\d+)\/?(\d+)?");
|
||||
readonly static Regex wild_regex = new Regex(@"(\*)");
|
||||
readonly static Regex list_regex = new Regex(@"(((\d+,)*\d+)+)");
|
||||
readonly static Regex validation_regex = new Regex(divided_regex + "|" + range_regex + "|" + wild_regex + "|" + list_regex);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Instance Members
|
||||
|
||||
private readonly string _expression;
|
||||
public List<int> seconds;
|
||||
public List<int> minutes;
|
||||
public List<int> hours;
|
||||
public List<int> days_of_month;
|
||||
public List<int> months;
|
||||
public List<int> days_of_week;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
public CronSchedule()
|
||||
{
|
||||
}
|
||||
|
||||
public CronSchedule(string expressions)
|
||||
{
|
||||
this._expression = expressions;
|
||||
generate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
private bool isValid()
|
||||
{
|
||||
return isValid(this._expression);
|
||||
}
|
||||
|
||||
public bool isValid(string expression)
|
||||
{
|
||||
MatchCollection matches = validation_regex.Matches(expression);
|
||||
return matches.Count > 0;//== 5;
|
||||
}
|
||||
|
||||
public bool isTime(DateTime date_time)
|
||||
{
|
||||
return seconds.Contains(date_time.Second) && minutes.Contains(date_time.Minute) &&
|
||||
hours.Contains(date_time.Hour) &&
|
||||
days_of_month.Contains(date_time.Day) &&
|
||||
months.Contains(date_time.Month) &&
|
||||
days_of_week.Contains((int)date_time.DayOfWeek);
|
||||
}
|
||||
|
||||
private void generate()
|
||||
{
|
||||
if (!isValid()) return;
|
||||
|
||||
MatchCollection matches = validation_regex.Matches(this._expression);
|
||||
generate_seconds(matches[0].ToString());
|
||||
|
||||
if (matches.Count > 1)
|
||||
generate_minutes(matches[1].ToString());
|
||||
else
|
||||
generate_minutes("*");
|
||||
if (matches.Count > 2)
|
||||
generate_hours(matches[2].ToString());
|
||||
else
|
||||
generate_hours("*");
|
||||
|
||||
if (matches.Count > 3)
|
||||
generate_days_of_month(matches[3].ToString());
|
||||
else
|
||||
generate_days_of_month("*");
|
||||
|
||||
if (matches.Count > 4)
|
||||
generate_months(matches[4].ToString());
|
||||
else
|
||||
generate_months("*");
|
||||
|
||||
if (matches.Count > 5)
|
||||
generate_days_of_weeks(matches[5].ToString());
|
||||
else
|
||||
generate_days_of_weeks("*");
|
||||
}
|
||||
private void generate_seconds(string match)
|
||||
{
|
||||
this.seconds = generate_values(match, 0, 60);
|
||||
}
|
||||
private void generate_minutes(string match)
|
||||
{
|
||||
this.minutes = generate_values(match, 0, 60);
|
||||
}
|
||||
|
||||
private void generate_hours(string match)
|
||||
{
|
||||
this.hours = generate_values(match, 0, 24);
|
||||
}
|
||||
|
||||
private void generate_days_of_month(string match)
|
||||
{
|
||||
this.days_of_month = generate_values(match, 1, 32);
|
||||
}
|
||||
|
||||
private void generate_months(string match)
|
||||
{
|
||||
this.months = generate_values(match, 1, 13);
|
||||
}
|
||||
|
||||
private void generate_days_of_weeks(string match)
|
||||
{
|
||||
this.days_of_week = generate_values(match, 0, 7);
|
||||
}
|
||||
|
||||
private List<int> generate_values(string configuration, int start, int max)
|
||||
{
|
||||
if (divided_regex.IsMatch(configuration)) return divided_array(configuration, start, max);
|
||||
if (range_regex.IsMatch(configuration)) return range_array(configuration);
|
||||
if (wild_regex.IsMatch(configuration)) return wild_array(configuration, start, max);
|
||||
if (list_regex.IsMatch(configuration)) return list_array(configuration);
|
||||
|
||||
return new List<int>();
|
||||
}
|
||||
|
||||
private List<int> divided_array(string configuration, int start, int max)
|
||||
{
|
||||
if (!divided_regex.IsMatch(configuration))
|
||||
return new List<int>();
|
||||
|
||||
List<int> ret = new List<int>();
|
||||
string[] split = configuration.Split("/".ToCharArray());
|
||||
int divisor = int.Parse(split[1]);
|
||||
|
||||
for (int i = start; i < max; ++i)
|
||||
if (i % divisor == 0)
|
||||
ret.Add(i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<int> range_array(string configuration)
|
||||
{
|
||||
if (!range_regex.IsMatch(configuration))
|
||||
return new List<int>();
|
||||
|
||||
List<int> ret = new List<int>();
|
||||
string[] split = configuration.Split("-".ToCharArray());
|
||||
int start = int.Parse(split[0]);
|
||||
int end = 0;
|
||||
if (split[1].Contains("/"))
|
||||
{
|
||||
split = split[1].Split("/".ToCharArray());
|
||||
end = int.Parse(split[0]);
|
||||
int divisor = int.Parse(split[1]);
|
||||
|
||||
for (int i = start; i < end; ++i)
|
||||
if (i % divisor == 0)
|
||||
ret.Add(i);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
end = int.Parse(split[1]);
|
||||
|
||||
for (int i = start; i <= end; ++i)
|
||||
ret.Add(i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<int> wild_array(string configuration, int start, int max)
|
||||
{
|
||||
if (!wild_regex.IsMatch(configuration))
|
||||
return new List<int>();
|
||||
|
||||
List<int> ret = new List<int>();
|
||||
|
||||
for (int i = start; i < max; ++i)
|
||||
ret.Add(i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<int> list_array(string configuration)
|
||||
{
|
||||
if (!list_regex.IsMatch(configuration))
|
||||
return new List<int>();
|
||||
|
||||
List<int> ret = new List<int>();
|
||||
|
||||
string[] split = configuration.Split(",".ToCharArray());
|
||||
|
||||
foreach (string s in split)
|
||||
ret.Add(int.Parse(s));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
120
src/Anno.EngineData/ActionResult.cs
Normal file
120
src/Anno.EngineData/ActionResult.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
public class ActionResult : ActionResult<object>
|
||||
{
|
||||
public ActionResult()
|
||||
{
|
||||
Output = new Dictionary<string, object>();
|
||||
this.Status = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
public ActionResult(Boolean status) : this()
|
||||
{
|
||||
this.Status = status;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
/// <param name="outputData">结果集</param>
|
||||
public ActionResult(Boolean status, object outputData) : this(status)
|
||||
{
|
||||
this.OutputData = outputData;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
/// <param name="outputData">结果集</param>
|
||||
/// <param name="output">字典</param>
|
||||
public ActionResult(Boolean status, object outputData, Dictionary<string, object> output) : this(status, outputData)
|
||||
{
|
||||
this.Output = output;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
/// <param name="outputData">结果集</param>
|
||||
/// <param name="output">字典</param>
|
||||
/// <param name="msg">消息</param>
|
||||
public ActionResult(Boolean status, object outputData, Dictionary<string, object> output, string msg) : this(status, outputData, output)
|
||||
{
|
||||
this.Msg = msg;
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionResult<T>: IActionResult
|
||||
{ /// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public Boolean Status { get; set; }
|
||||
/// <summary>
|
||||
/// 消息
|
||||
/// </summary>
|
||||
public string Msg { get; set; }
|
||||
/// <summary>
|
||||
/// 字典
|
||||
/// </summary>
|
||||
public Dictionary<string, object> Output { get; set; }
|
||||
/// <summary>
|
||||
/// 结果集
|
||||
/// </summary>
|
||||
public T OutputData { get; set; }
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ActionResult()
|
||||
{
|
||||
Output = new Dictionary<string, object>();
|
||||
this.Status = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
public ActionResult(Boolean status) : this()
|
||||
{
|
||||
this.Status = status;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
/// <param name="outputData">结果集</param>
|
||||
public ActionResult(Boolean status, T outputData) : this(status)
|
||||
{
|
||||
this.OutputData = outputData;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
/// <param name="outputData">结果集</param>
|
||||
/// <param name="output">字典</param>
|
||||
public ActionResult(Boolean status, T outputData, Dictionary<string, object> output) : this(status, outputData)
|
||||
{
|
||||
this.Output = output;
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="status">状态</param>
|
||||
/// <param name="outputData">结果集</param>
|
||||
/// <param name="output">字典</param>
|
||||
/// <param name="msg">消息</param>
|
||||
public ActionResult(Boolean status, T outputData, Dictionary<string, object> output, string msg) : this(status, outputData, output)
|
||||
{
|
||||
this.Msg = msg;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IActionResult { }
|
||||
}
|
||||
29
src/Anno.EngineData/Anno.EngineData.csproj
Normal file
29
src/Anno.EngineData/Anno.EngineData.csproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTfms);net461</TargetFrameworks>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>Du yanming</Authors>
|
||||
<Company>Du yanming</Company>
|
||||
<Product>Anno 数据处理引擎</Product>
|
||||
<Description>分布式开发框架 数据处理器</Description>
|
||||
<PackageProjectUrl>https://github.com/duyanming/Viper</PackageProjectUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="SysInfo\ConnectorWatch.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--<ProjectReference Include="..\..\DCS\Grpc\Anno.Rpc.ClientGrpc\Anno.Rpc.ClientGrpc.csproj" />-->
|
||||
<!--<ProjectReference Include="..\..\DCS\Anno.Rpc.Client\Anno.Rpc.Client.csproj" />-->
|
||||
<ProjectReference Include="..\Anno.CronNET\Anno.CronNET.csproj" />
|
||||
<ProjectReference Include="..\Anno.Loader\Anno.Loader.csproj" />
|
||||
<ProjectReference Include="..\Anno.Log\Anno.Log.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
184
src/Anno.EngineData/AnnoBootstrap.cs
Normal file
184
src/Anno.EngineData/AnnoBootstrap.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using Anno.EngineData.Filters;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
public static class AnnoBootstrap
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件启动配置
|
||||
/// </summary>
|
||||
/// <param name="iocAction">用于用户自定义做依赖注入</param>
|
||||
public static void Bootstrap(Action iocAction)
|
||||
{
|
||||
Const.SettingService.InitConfig();
|
||||
iocAction?.Invoke();
|
||||
PreConfigurationBootstrap();
|
||||
Loader.IocLoader.Build();
|
||||
var bootstraps = Loader.IocLoader.Resolve<IEnumerable<IPlugsConfigurationBootstrap>>();
|
||||
if (bootstraps != null)
|
||||
{
|
||||
foreach (var plugsConfigurationBootstrap in bootstraps)
|
||||
{
|
||||
plugsConfigurationBootstrap.ConfigurationBootstrap();
|
||||
}
|
||||
}
|
||||
BuilderRouterInfo();
|
||||
}
|
||||
/// <summary>
|
||||
/// IOC注入之前插件事件
|
||||
/// </summary>
|
||||
private static void PreConfigurationBootstrap()
|
||||
{
|
||||
foreach (var svc in Const.Assemblys.Dic)
|
||||
{
|
||||
GetDependedTypesAssemblies(svc.Value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 查找依赖
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <returns></returns>
|
||||
static void GetDependedTypesAssemblies(Assembly assembly)
|
||||
{
|
||||
List<Assembly> assemblies = new List<Assembly>();
|
||||
var type = assembly.GetTypes().FirstOrDefault(t => typeof(IPlugsConfigurationBootstrap).IsAssignableFrom(t));
|
||||
if (type == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var obj = Activator.CreateInstance(type);
|
||||
type.GetMethod("PreConfigurationBootstrap")?.Invoke(obj, null);
|
||||
var dependsOn = type.GetCustomAttributes<DependsOnAttribute>().FirstOrDefault();
|
||||
if (dependsOn != null)
|
||||
{
|
||||
foreach (var module in dependsOn.DependedTypes)
|
||||
{
|
||||
if (Const.Assemblys.Dic.Values.ToList().Exists(s => s == module.Assembly) || Const.Assemblys.DependedTypes.Exists(s => s == module.Assembly))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Const.Assemblys.DependedTypes.Add(module.Assembly);
|
||||
assemblies.Add(module.Assembly);
|
||||
}
|
||||
}
|
||||
if (assemblies.Count() > 0)
|
||||
{
|
||||
foreach (var module in assemblies)
|
||||
{
|
||||
GetDependedTypesAssemblies(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 构建路由信息
|
||||
/// </summary>
|
||||
static void BuilderRouterInfo()
|
||||
{
|
||||
var baseModuleType = typeof(BaseModule);
|
||||
foreach (var svc in Const.Assemblys.Dic)
|
||||
{
|
||||
svc.Value.GetTypes().Where(x => x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract && !x.GetTypeInfo().IsInterface
|
||||
&& baseModuleType.IsAssignableFrom(x)).ToList().ForEach(t =>
|
||||
{
|
||||
var methods = t.GetMethods().Where(m => !m.DeclaringType.Equals(baseModuleType) && !m.DeclaringType.Equals(typeof(object)) && m.IsPublic && !m.IsAbstract && !m.IsConstructor && !m.IsVirtual);
|
||||
foreach (var method in methods)
|
||||
{
|
||||
Routing.RoutInfo routInfo = new Routing.RoutInfo()
|
||||
{
|
||||
RoutMethod = method,
|
||||
RoutModuleType = t
|
||||
};
|
||||
#region Authorization Filters
|
||||
/*
|
||||
* 全局过滤器
|
||||
*/
|
||||
routInfo.AuthorizationFilters.AddRange(Routing.Routing.GlobalAuthorizationFilters);
|
||||
/*
|
||||
* 模块过滤器
|
||||
*/
|
||||
routInfo.AuthorizationFilters.AddRange(t.GetCustomAttributes<AuthorizationFilterAttribute>());
|
||||
/*
|
||||
* 方法过滤器
|
||||
*/
|
||||
routInfo.AuthorizationFilters.AddRange(method.GetCustomAttributes<AuthorizationFilterAttribute>());
|
||||
#endregion
|
||||
#region Action Filters
|
||||
/*
|
||||
* 全局过滤器
|
||||
*/
|
||||
routInfo.ActionFilters.AddRange(Routing.Routing.GlobalActionFilters);
|
||||
/*
|
||||
* 模块过滤器
|
||||
*/
|
||||
routInfo.ActionFilters.AddRange(routInfo.RoutModuleType.GetCustomAttributes<ActionFilterAttribute>());
|
||||
/*
|
||||
* 方法过滤器
|
||||
*/
|
||||
routInfo.ActionFilters.AddRange(routInfo.RoutMethod.GetCustomAttributes<ActionFilterAttribute>());
|
||||
#endregion
|
||||
#region Exception Filters
|
||||
/*
|
||||
* 方法过滤器
|
||||
*/
|
||||
routInfo.ExceptionFilters.AddRange(routInfo.RoutMethod.GetCustomAttributes<ExceptionFilterAttribute>());
|
||||
/*
|
||||
* 模块过滤器
|
||||
*/
|
||||
routInfo.ExceptionFilters.AddRange(routInfo.RoutModuleType.GetCustomAttributes<ExceptionFilterAttribute>());
|
||||
/*
|
||||
* 全局过滤器
|
||||
*/
|
||||
routInfo.ExceptionFilters.AddRange(Routing.Routing.GlobalExceptionFilters);
|
||||
#endregion
|
||||
#region CacheMiddleware
|
||||
/*
|
||||
* 全局Cache
|
||||
*/
|
||||
routInfo.CacheMiddleware.AddRange(Routing.Routing.GlobalCacheMiddleware);
|
||||
/*
|
||||
* 模块Cache
|
||||
*/
|
||||
routInfo.CacheMiddleware.AddRange(routInfo.RoutModuleType.GetCustomAttributes<Cache.CacheMiddlewareAttribute>());
|
||||
/*
|
||||
* 方法Cache
|
||||
*/
|
||||
routInfo.CacheMiddleware.AddRange(routInfo.RoutMethod.GetCustomAttributes<Cache.CacheMiddlewareAttribute>());
|
||||
#endregion
|
||||
var key = $"{t.FullName}/{method.Name}";
|
||||
if (Routing.Routing.Router.ContainsKey(key))
|
||||
{
|
||||
Routing.Routing.Router[key] = routInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
Routing.Routing.Router.TryAdd(key, routInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
static bool IsAssignableFrom(Type type, string baseTypeFullName)
|
||||
{
|
||||
bool success = false;
|
||||
if (type == null)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
else if (type.FullName == baseTypeFullName)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
else if (type.BaseType != null)
|
||||
{
|
||||
success = IsAssignableFrom(type.BaseType, baseTypeFullName);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/Anno.EngineData/AnnoInvokeEngineException.cs
Normal file
40
src/Anno.EngineData/AnnoInvokeEngineException.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
/// <summary>
|
||||
/// InvokeEngine 集群服务间调用异常
|
||||
/// </summary>
|
||||
public class AnnoInvokeEngineException:Exception
|
||||
{
|
||||
public enum AnnoInvokeEngineExceptionType
|
||||
{
|
||||
//超时异常
|
||||
Timeout,
|
||||
//参数异常
|
||||
Argument,
|
||||
//服务端捕获异常
|
||||
ServerCaptured,
|
||||
//服务端未知异常
|
||||
ServerUnkown,
|
||||
//请求数据异常
|
||||
InvalidRequestPara
|
||||
}
|
||||
public AnnoInvokeEngineExceptionType Type { get; set; }
|
||||
public AnnoInvokeEngineException(AnnoInvokeEngineExceptionType type)
|
||||
{
|
||||
this.Type = type;
|
||||
}
|
||||
public AnnoInvokeEngineException(AnnoInvokeEngineExceptionType type, string message)
|
||||
: base(message)
|
||||
{
|
||||
this.Type = type;
|
||||
}
|
||||
public AnnoInvokeEngineException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/Anno.EngineData/Attribute/DependsOnAttribute.cs
Normal file
25
src/Anno.EngineData/Attribute/DependsOnAttribute.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于定义类型的依赖项。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
public class DependsOnAttribute : Attribute
|
||||
{
|
||||
public Type[] DependedTypes { get; }
|
||||
|
||||
public DependsOnAttribute(params Type[] dependedTypes)
|
||||
{
|
||||
DependedTypes = dependedTypes ?? new Type[0];
|
||||
}
|
||||
|
||||
public virtual Type[] GetDependedTypes()
|
||||
{
|
||||
return DependedTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/Anno.EngineData/Attribute/FromBodyAttribute.cs
Normal file
13
src/Anno.EngineData/Attribute/FromBodyAttribute.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
/// <summary>
|
||||
/// FromBody 标记
|
||||
/// </summary>
|
||||
public class FromBodyAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
388
src/Anno.EngineData/BaseModule.cs
Normal file
388
src/Anno.EngineData/BaseModule.cs
Normal file
@@ -0,0 +1,388 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Anno.Const.Enum;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
public abstract class BaseModule : InvokeEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否通过了授权
|
||||
/// </summary>
|
||||
public bool Authorized { get; set; } = false;
|
||||
public const string Table = "__table__";
|
||||
/// <summary>
|
||||
/// FormInput信息
|
||||
/// </summary>
|
||||
private Dictionary<string, string> _input;
|
||||
|
||||
/// <summary>
|
||||
/// FormInput信息
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Input => _input;
|
||||
|
||||
/// <summary>
|
||||
/// 前置初始化方法
|
||||
/// </summary>
|
||||
/// <param name="input">表单数据</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public virtual bool Init(Dictionary<string, string> input)
|
||||
{
|
||||
this._input = input;
|
||||
return true;
|
||||
}
|
||||
|
||||
public new string InvokeProcessor(string channel, string router, string method, Dictionary<string, string> response)
|
||||
{
|
||||
/*
|
||||
* 采用复制品 发送请求。防止修改当前上下文对象Input
|
||||
*/
|
||||
if (response.Equals(Input))
|
||||
{
|
||||
var responseReplica=new Dictionary<string,string>();
|
||||
foreach (var dic in response)
|
||||
{
|
||||
responseReplica.Add(dic.Key,dic.Value);
|
||||
}
|
||||
return InvokeEngine.InvokeProcessor(channel, router, method, responseReplica);
|
||||
}
|
||||
|
||||
if (!response.ContainsKey("TraceId"))
|
||||
{
|
||||
response.Add("TraceId",RequestString("TraceId"));
|
||||
}
|
||||
if (!response.ContainsKey("PreTraceId"))
|
||||
{
|
||||
response.Add("PreTraceId", RequestString("PreTraceId"));
|
||||
}
|
||||
if (!response.ContainsKey("TTL"))
|
||||
{
|
||||
response.Add("TTL", RequestString("TTL"));
|
||||
}
|
||||
if (!response.ContainsKey("GlobalTraceId"))
|
||||
{
|
||||
response.Add("GlobalTraceId", RequestString("GlobalTraceId"));
|
||||
}
|
||||
return InvokeEngine.InvokeProcessor(channel, router, method, response);
|
||||
}
|
||||
public new Task<string> InvokeProcessorAsync(string channel, string router, string method, Dictionary<string, string> response)
|
||||
{
|
||||
/*
|
||||
* 采用复制品 发送请求。防止修改当前上下文对象Input
|
||||
*/
|
||||
if (response.Equals(_input))
|
||||
{
|
||||
var responseReplica = new Dictionary<string, string>();
|
||||
foreach (var dic in response)
|
||||
{
|
||||
responseReplica.Add(dic.Key, dic.Value);
|
||||
}
|
||||
return InvokeEngine.InvokeProcessorAsync(channel, router, method, responseReplica);
|
||||
}
|
||||
|
||||
if (!response.ContainsKey("TraceId"))
|
||||
{
|
||||
response.Add("TraceId", RequestString("TraceId"));
|
||||
}
|
||||
if (!response.ContainsKey("PreTraceId"))
|
||||
{
|
||||
response.Add("PreTraceId", RequestString("PreTraceId"));
|
||||
}
|
||||
if (!response.ContainsKey("TTL"))
|
||||
{
|
||||
response.Add("TTL", RequestString("TTL"));
|
||||
}
|
||||
if (!response.ContainsKey("GlobalTraceId"))
|
||||
{
|
||||
response.Add("GlobalTraceId", RequestString("GlobalTraceId"));
|
||||
}
|
||||
return InvokeEngine.InvokeProcessorAsync(channel, router, method, response);
|
||||
}
|
||||
|
||||
#region AutoFac+Resolve
|
||||
/// <summary>
|
||||
/// AutoFac 获取实例对象
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实例对象</typeparam>
|
||||
/// <returns></returns>
|
||||
public T Resolve<T>()
|
||||
{
|
||||
return Loader.IocLoader.Resolve<T>();
|
||||
}
|
||||
public T Resolve<T>(Type serviceType) where T : class
|
||||
{
|
||||
return Loader.IocLoader.Resolve<T>(serviceType);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Request+获取请求上下文
|
||||
/// <summary>
|
||||
/// 获取序列化对象
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型</typeparam>
|
||||
/// <param name="key">对象键值</param>
|
||||
/// <returns></returns>
|
||||
public T Request<T>(string key) where T : class, new()
|
||||
{
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(RequestString(key));
|
||||
}
|
||||
return default(T);
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 Int16
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>Int16 Value</returns>
|
||||
public Int16? RequestInt16(string key)
|
||||
{
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToInt16(GetValueByKey(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 Int32
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>Int32 Value</returns>
|
||||
public Int32? RequestInt32(string key)
|
||||
{
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToInt32(GetValueByKey(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 Int64
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>Int64 Value</returns>
|
||||
public Int64? RequestInt64(string key)
|
||||
{
|
||||
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToInt64(GetValueByKey(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 Boolean
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>Boolean Value</returns>
|
||||
public Boolean? RequestBoolean(string key)
|
||||
{
|
||||
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToBoolean(GetValueByKey(key).ToLower());
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 DateTime
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>DateTime Value</returns>
|
||||
public DateTime? RequestDateTime(string key)
|
||||
{
|
||||
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToDateTime(GetValueByKey(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 Decimal
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>Decimal Value</returns>
|
||||
public Decimal? RequestDecimal(string key)
|
||||
{
|
||||
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToDecimal(GetValueByKey(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 Double
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>Double Value</returns>
|
||||
public Double? RequestDouble(string key)
|
||||
{
|
||||
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToDouble(GetValueByKey(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 float
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>float Value</returns>
|
||||
public float? RequestSingle(string key)
|
||||
{
|
||||
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return Convert.ToSingle(GetValueByKey(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据键获取值 string
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>string Value</returns>
|
||||
public string RequestString(string key)
|
||||
{
|
||||
return GetValueByKey(key);
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据Key 获取字符串值
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <returns>字符串值</returns>
|
||||
private string GetValueByKey(string key)
|
||||
{
|
||||
if (RequestContainsKey(key))
|
||||
{
|
||||
return _input[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 上下文是否包含 key
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool RequestContainsKey(string key)
|
||||
{
|
||||
return _input.ContainsKey(key);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取Request 键值集合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<string> RequestKeys()
|
||||
{
|
||||
return _input.Keys.ToList();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取前端列表的过滤条件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Filter()
|
||||
{
|
||||
string where = string.Empty;
|
||||
var groups = Request<Group>("where");
|
||||
if (groups != null && groups.rules.Count > 0)
|
||||
{
|
||||
where = ExpressionAnalysis.TransmitFilter(groups, Table);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(where))
|
||||
{
|
||||
where = " 1=1 ";
|
||||
}
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 用户身份令牌
|
||||
/// </summary>
|
||||
public ProfileToken Profile { get; set; }
|
||||
/// <summary>
|
||||
/// 执行结果
|
||||
/// </summary>
|
||||
public ActionResult ActionResult { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileToken
|
||||
{
|
||||
#region 属性
|
||||
|
||||
public long ID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Account { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Pwd { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public long Coid { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Position { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public short? State { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Profile { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime? Timespan { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime? Rdt { get; set; }
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
16
src/Anno.EngineData/Cache/CacheMiddlewareAttribute.cs
Normal file
16
src/Anno.EngineData/Cache/CacheMiddlewareAttribute.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Anno.EngineData.Filters;
|
||||
using Anno.EngineData.Routing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Cache
|
||||
{
|
||||
public abstract class CacheMiddlewareAttribute : Attribute, ICacheMiddleware, IFilterMetadata
|
||||
{
|
||||
public abstract void RemoveCache(string key);
|
||||
|
||||
public abstract void SetCache(string key, ActionResult actionResult);
|
||||
public abstract bool TryGetCache(string key, out ActionResult actionResult);
|
||||
}
|
||||
}
|
||||
14
src/Anno.EngineData/Cache/ICacheMiddleware.cs
Normal file
14
src/Anno.EngineData/Cache/ICacheMiddleware.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Anno.EngineData.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Cache
|
||||
{
|
||||
public interface ICacheMiddleware : IFilterMetadata
|
||||
{
|
||||
bool TryGetCache(string key, out ActionResult actionResult);
|
||||
void SetCache(string key, ActionResult actionResult);
|
||||
void RemoveCache(string key);
|
||||
}
|
||||
}
|
||||
109
src/Anno.EngineData/DLock.cs
Normal file
109
src/Anno.EngineData/DLock.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
/// <summary>
|
||||
/// 分布式锁
|
||||
/// </summary>
|
||||
public class DLock : IDisposable
|
||||
{
|
||||
private string channel = "Anno.Plugs.DLock";
|
||||
private string router = "DLock";
|
||||
private bool _disposed;
|
||||
private bool _getLockStatus = false;
|
||||
private readonly string _key;
|
||||
|
||||
/// <summary>
|
||||
/// 超时时间
|
||||
/// </summary>
|
||||
private readonly int _timeOut = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// 所有者
|
||||
/// </summary>
|
||||
private readonly string _owner;
|
||||
/// <summary>
|
||||
/// 分布式锁
|
||||
/// </summary>
|
||||
/// <param name="key">锁可以</param>
|
||||
/// <param name="timeOut">锁超时时间 Default 5000 毫秒 最小1000毫秒。</param>
|
||||
public DLock(string key, int timeOut = 5000)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
throw new DLockException($"锁Key不能为null或者string.Empty");
|
||||
}
|
||||
if (timeOut < 1000)
|
||||
{
|
||||
timeOut = 1000;
|
||||
}
|
||||
_disposed = false;
|
||||
_key = key;
|
||||
this._timeOut = timeOut;
|
||||
_owner = Const.SettingService.AppName + "_" + Guid.NewGuid().ToString("N") + System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
EnterLock();
|
||||
}
|
||||
|
||||
private DLock()
|
||||
{
|
||||
}
|
||||
~DLock()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
private void EnterLock()
|
||||
{
|
||||
var response = new Dictionary<string, string>();
|
||||
response.Add("DLKey", _key);
|
||||
response.Add("TimeOut", _timeOut.ToString());
|
||||
response.Add("Owner", _owner);
|
||||
var rltStr = InvokeEngine.InvokeProcessor(channel, router, "EnterLock", response);
|
||||
var rlt = Newtonsoft.Json.JsonConvert.DeserializeObject<ActionResult>(rltStr);
|
||||
if (!rlt.Status)
|
||||
{
|
||||
throw new DLockException("EnterLock Error:" + rlt.Msg);
|
||||
}
|
||||
_getLockStatus = true;
|
||||
}
|
||||
private void DisposeLock()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_getLockStatus)
|
||||
{
|
||||
var response = new Dictionary<string, string>();
|
||||
response.Add("DLKey", _key);
|
||||
response.Add("Owner", _owner);
|
||||
InvokeEngine.InvokeProcessor(channel, router, "DisposeLock", response);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//throw new DLockException("DisposeLock:" + e.Message);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 释放锁
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
DisposeLock();
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Anno.EngineData/DLockException.cs
Normal file
16
src/Anno.EngineData/DLockException.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
/// <summary>
|
||||
/// 分布式锁异常
|
||||
/// </summary>
|
||||
public class DLockException : Exception
|
||||
{
|
||||
public DLockException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
296
src/Anno.EngineData/Engine.cs
Normal file
296
src/Anno.EngineData/Engine.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Anno.Const.Enum;
|
||||
using Anno.EngineData.Filters;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据集散中心
|
||||
/// </summary>
|
||||
public static class Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// 转发器
|
||||
/// </summary>
|
||||
/// <param name="input">表单数据</param>
|
||||
/// <returns></returns>
|
||||
public static ActionResult Transmit(Dictionary<string, string> input)
|
||||
{
|
||||
#region 查找System.Type
|
||||
var key = $"{input[Eng.NAMESPACE]}Service.{input[Eng.CLASS]}Module/{input[Eng.METHOD]}";
|
||||
if (Routing.Routing.Router.TryGetValue(key, out Routing.RoutInfo routInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
return Transmit(input, routInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//记录日志
|
||||
Log.Log.Error(ex, routInfo.RoutModuleType);
|
||||
return new ActionResult()
|
||||
{
|
||||
Status = false,
|
||||
OutputData = null,
|
||||
Msg = ex.InnerException?.Message ?? ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ActionResult()
|
||||
{
|
||||
Status = false,
|
||||
OutputData = null,
|
||||
Msg = $"在【{input[Eng.NAMESPACE]}】中找不到【{input[Eng.CLASS]}.{input[Eng.METHOD]}】!"
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// 转发器异步
|
||||
/// </summary>
|
||||
/// <param name="input">表单数据</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<ActionResult> TransmitAsync(Dictionary<string, string> input)
|
||||
{
|
||||
return await Task.Run(() => Transmit(input));
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据服务转发
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="type">表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型</param>
|
||||
/// <returns></returns>
|
||||
public static ActionResult Transmit(Dictionary<string, string> input, Routing.RoutInfo routInfo)
|
||||
{
|
||||
BaseModule module = null;
|
||||
try
|
||||
{
|
||||
#region Cache
|
||||
string key = string.Empty;
|
||||
if (routInfo.CacheMiddleware.Count > 0)
|
||||
{
|
||||
key = GetDicStrHashCode(input);
|
||||
if (TryGetCache(routInfo, key, out ActionResult rltCache))
|
||||
{
|
||||
return rltCache;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
List<object> lo = new List<object>() { input };
|
||||
module = Loader.IocLoader.Resolve<BaseModule>(routInfo.RoutModuleType); //创建实例(无参构造器)
|
||||
var init = module.Init(input);
|
||||
if (!init)
|
||||
{
|
||||
return new ActionResult()
|
||||
{
|
||||
Status = false,
|
||||
Msg = "Init拦截!"
|
||||
};
|
||||
}
|
||||
if (routInfo.RoutMethod == null)
|
||||
{
|
||||
return new ActionResult()
|
||||
{
|
||||
Status = false,
|
||||
OutputData = null,
|
||||
Msg = $"在【{input[Eng.NAMESPACE]}】中找不到【{input[Eng.CLASS]}.{input[Eng.METHOD]}】!"
|
||||
};
|
||||
}
|
||||
#region Authorization
|
||||
for (int i = 0; i < routInfo.AuthorizationFilters.Count; i++)
|
||||
{
|
||||
routInfo.AuthorizationFilters[i].OnAuthorization(module);
|
||||
if (!module.Authorized)
|
||||
{
|
||||
return new ActionResult()
|
||||
{
|
||||
Status = false,
|
||||
OutputData = 401,
|
||||
Msg = "401,Unauthrized"
|
||||
};
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
for (int i = 0; i < routInfo.ActionFilters.Count; i++)
|
||||
{
|
||||
routInfo.ActionFilters[i].OnActionExecuting(module);
|
||||
}
|
||||
var rltCustomize = routInfo.RoutMethod.Invoke(module, DicToParameters(routInfo.RoutMethod, input).ToArray());
|
||||
if (rltCustomize != null && typeof(IActionResult).IsAssignableFrom(rltCustomize.GetType()))
|
||||
{
|
||||
module.ActionResult = rltCustomize as ActionResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
module.ActionResult = new ActionResult(true, rltCustomize);
|
||||
}
|
||||
for (int i = (routInfo.ActionFilters.Count - 1); i >= 0; i--)
|
||||
{
|
||||
routInfo.ActionFilters[i].OnActionExecuted(module);
|
||||
}
|
||||
if (routInfo.CacheMiddleware.Count > 0)
|
||||
{
|
||||
AddCache(routInfo, key, module.ActionResult);
|
||||
}
|
||||
return module.ActionResult;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (routInfo.RoutMethod != null)
|
||||
{
|
||||
foreach (var ef in routInfo.ExceptionFilters)
|
||||
{
|
||||
ef.OnException(ex, module);
|
||||
}
|
||||
}
|
||||
//记录日志
|
||||
Log.Log.Error(ex, routInfo.RoutModuleType);
|
||||
return new ActionResult()
|
||||
{
|
||||
Status = false,
|
||||
OutputData = null,
|
||||
Msg = ex.InnerException?.Message ?? ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据服务转发
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="type">表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<ActionResult> TransmitAsync(Dictionary<string, string> input, Routing.RoutInfo routInfo)
|
||||
{
|
||||
return await Task.Run(() => Transmit(input, routInfo));
|
||||
}
|
||||
/// <summary>
|
||||
/// 扩展属性校验
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
private static List<object> DicToParameters(MethodInfo method, Dictionary<string, string> input)
|
||||
{
|
||||
List<object> parameters = new List<object>();
|
||||
foreach (var p in method.GetParameters())
|
||||
{
|
||||
if (p.GetCustomAttributes<FromBodyAttribute>().Any())
|
||||
{
|
||||
parameters.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(Newtonsoft.Json.JsonConvert.SerializeObject(input), p.ParameterType));
|
||||
continue;
|
||||
}
|
||||
else if (input.ContainsKey(p.Name))
|
||||
{
|
||||
if (p.ParameterType.FullName.IndexOf("System", StringComparison.Ordinal) != -1)//系统基础数据类型
|
||||
{
|
||||
parameters.Add(Convert.ChangeType(input[p.Name], p.ParameterType));//枚举
|
||||
}
|
||||
else if (p.ParameterType.BaseType == typeof(Enum))
|
||||
{
|
||||
|
||||
parameters.Add(Enum.Parse(p.ParameterType, input[p.Name]));
|
||||
}
|
||||
else // 系统基础数据类型、枚举 之外。例如 结构体、类、匿名对象
|
||||
{
|
||||
parameters.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(input[p.Name], p.ParameterType));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters.Add(default);
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static bool TryGetCache(Routing.RoutInfo routInfo, string key, out ActionResult actionResult)
|
||||
{
|
||||
actionResult = null;
|
||||
for (int i = 0; i < routInfo.CacheMiddleware.Count; i++)
|
||||
{
|
||||
var cm = routInfo.CacheMiddleware[i];
|
||||
if (cm.TryGetCache(key, out actionResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static void AddCache(Routing.RoutInfo routInfo, string key, ActionResult actionResult)
|
||||
{
|
||||
for (int i = 0; i < routInfo.CacheMiddleware.Count; i++)
|
||||
{
|
||||
var cm = routInfo.CacheMiddleware[i];
|
||||
cm.SetCache(key, actionResult);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDicStrHashCode(Dictionary<string, string> input)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
foreach (var item in input)
|
||||
{
|
||||
if (item.Key == "X-Original-For"
|
||||
|| item.Key == "profile"
|
||||
|| item.Key == "TraceId"
|
||||
|| item.Key == "PreTraceId"
|
||||
|| item.Key == "GlobalTraceId"
|
||||
|| item.Key == "AppName"
|
||||
|| item.Key == "Target"
|
||||
|| item.Key == "AppNameTarget"
|
||||
|| item.Key == "TTL"
|
||||
|| item.Key == "t"
|
||||
)//排除系统内置参数
|
||||
{
|
||||
continue;
|
||||
}
|
||||
stringBuilder.Append(item.Key);
|
||||
stringBuilder.Append(item.Value);
|
||||
}
|
||||
return stringBuilder.ToString().HashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算文件的哈希值
|
||||
/// </summary>
|
||||
/// <param name="buffer">被操作的源数据流</param>
|
||||
/// <param name="algo">加密算法</param>
|
||||
/// <returns>哈希值16进制字符串</returns>
|
||||
private static string HashCode(this string str, string algo = "md5")
|
||||
{
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(str);
|
||||
HashAlgorithm hashAlgorithm = null;
|
||||
switch (algo)
|
||||
{
|
||||
case "sha1":
|
||||
hashAlgorithm = new SHA1CryptoServiceProvider();
|
||||
break;
|
||||
case "md5":
|
||||
hashAlgorithm = new MD5CryptoServiceProvider();
|
||||
break;
|
||||
default:
|
||||
hashAlgorithm = new MD5CryptoServiceProvider();
|
||||
break;
|
||||
}
|
||||
|
||||
var hash = hashAlgorithm.ComputeHash(buffer);
|
||||
var sb = new StringBuilder();
|
||||
foreach (var t in hash)
|
||||
{
|
||||
sb.Append(t.ToString("x2"));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
107
src/Anno.EngineData/ExpressionAnalysis.cs
Normal file
107
src/Anno.EngineData/ExpressionAnalysis.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
public class ExpressionAnalysis
|
||||
{
|
||||
public static string TransmitFilter(Group group,string table)
|
||||
{
|
||||
group.rules.RemoveAll(r => r.field == "undefined");
|
||||
List<Rule> rules = group.rules;
|
||||
if (rules == null || rules.Count == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
StringBuilder where = new StringBuilder();
|
||||
where.AppendFormat("(");
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
where.Append(GetFilter(rule,table));
|
||||
where.Append(" and ");
|
||||
}
|
||||
|
||||
where.Remove(where.Length - 5, 5);
|
||||
if (group.groups != null && group.groups.Count(g => g.rules.Count(r => r.field != "undefined") > 0) > 0)
|
||||
{
|
||||
where.AppendFormat($" {group.op} ");
|
||||
where.AppendFormat("(");
|
||||
int spLength = " {g.op} ".Length;
|
||||
group.groups.Where(g => g.rules.Count(r => r.field != "undefined") > 0).ToList().ForEach(g =>
|
||||
{
|
||||
where.AppendFormat(TransmitFilter(g, table));
|
||||
where.AppendFormat($" {g.op} ");
|
||||
});
|
||||
if (group.groups.Count(g => g.rules.Count(r => r.field != "undefined") > 0) > 0)
|
||||
{
|
||||
where.Remove(where.Length - spLength, spLength);
|
||||
where.AppendFormat(")");
|
||||
}
|
||||
where.AppendFormat(")");
|
||||
}
|
||||
where.AppendFormat(")");
|
||||
return where.ToString();
|
||||
}
|
||||
|
||||
private static string GetFilter(Rule rule,string table)
|
||||
{
|
||||
string where = string.Empty;
|
||||
var field = rule.field;
|
||||
field = field.Replace(table, ".");
|
||||
switch (rule.op)
|
||||
{
|
||||
case "equal":
|
||||
return $" {field}={GetValue(rule.type, rule.value)} ";
|
||||
case "notequal":
|
||||
return $" {field}<>{GetValue(rule.type, rule.value)} ";
|
||||
case "startwith":
|
||||
return $" {field} like '{rule.value}%' ";
|
||||
case "endwith":
|
||||
return $" {field} like '%{rule.value}' ";
|
||||
case "like":
|
||||
return $" {field} like '%{rule.value}%' ";
|
||||
case "greater":
|
||||
return $" {rule.field}>{GetValue(rule.type, rule.value)} ";
|
||||
case "greaterorequal":
|
||||
return $" {field}>={GetValue(rule.type, rule.value)} ";
|
||||
case "less":
|
||||
return $" {field}<{GetValue(rule.type, rule.value)} ";
|
||||
case "lessorequal":
|
||||
return $" {field}<={GetValue(rule.type, rule.value)} ";
|
||||
case "in":
|
||||
return $" {field} in ({rule.value}) ";
|
||||
case "notin":
|
||||
return $" {field} not in ({rule.value}) ";
|
||||
}
|
||||
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
private static string GetValue(string type, string value)
|
||||
{
|
||||
|
||||
if (type == "number" || type == "int" || type == "float")
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return $"'{value}'";
|
||||
}
|
||||
}
|
||||
public class Rule
|
||||
{
|
||||
public string field { get; set; }
|
||||
public string op { get; set; }
|
||||
public string value { get; set; }
|
||||
public string type { get; set; }
|
||||
}
|
||||
|
||||
public class Group
|
||||
{
|
||||
public List<Rule> rules { get; set; }
|
||||
public List<Group> groups { get; set; }
|
||||
public string op { get; set; }
|
||||
}
|
||||
}
|
||||
19
src/Anno.EngineData/Filters/ActionFilterAttribute.cs
Normal file
19
src/Anno.EngineData/Filters/ActionFilterAttribute.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Filters
|
||||
{
|
||||
public abstract class ActionFilterAttribute: Attribute, IActionFilter, IFilterMetadata
|
||||
{
|
||||
public virtual void OnActionExecuted(BaseModule context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnActionExecuting(BaseModule context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/Anno.EngineData/Filters/AuthorizationFilterAttribute.cs
Normal file
14
src/Anno.EngineData/Filters/AuthorizationFilterAttribute.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Filters
|
||||
{
|
||||
public abstract class AuthorizationFilterAttribute : Attribute, IAuthorizationFilter, IFilterMetadata
|
||||
{
|
||||
public virtual void OnAuthorization(BaseModule context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/Anno.EngineData/Filters/ExceptionFilterAttribute.cs
Normal file
14
src/Anno.EngineData/Filters/ExceptionFilterAttribute.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Filters
|
||||
{
|
||||
public abstract class ExceptionFilterAttribute : Attribute, IExceptionFilter, IFilterMetadata
|
||||
{
|
||||
public virtual void OnException(Exception ex, BaseModule context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/Anno.EngineData/Filters/IActionFilter.cs
Normal file
12
src/Anno.EngineData/Filters/IActionFilter.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Filters
|
||||
{
|
||||
public interface IActionFilter : IFilterMetadata
|
||||
{
|
||||
void OnActionExecuted(BaseModule context);
|
||||
void OnActionExecuting(BaseModule context);
|
||||
}
|
||||
}
|
||||
11
src/Anno.EngineData/Filters/IAuthorizationFilter.cs
Normal file
11
src/Anno.EngineData/Filters/IAuthorizationFilter.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Filters
|
||||
{
|
||||
public interface IAuthorizationFilter : IFilterMetadata
|
||||
{
|
||||
void OnAuthorization(BaseModule context);
|
||||
}
|
||||
}
|
||||
11
src/Anno.EngineData/Filters/IExceptionFilter.cs
Normal file
11
src/Anno.EngineData/Filters/IExceptionFilter.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Filters
|
||||
{
|
||||
public interface IExceptionFilter:IFilterMetadata
|
||||
{
|
||||
void OnException(Exception ex,BaseModule context);
|
||||
}
|
||||
}
|
||||
10
src/Anno.EngineData/Filters/IFilterMetadata.cs
Normal file
10
src/Anno.EngineData/Filters/IFilterMetadata.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.Filters
|
||||
{
|
||||
public interface IFilterMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
21
src/Anno.EngineData/IPlugsConfigurationBootstrap.cs
Normal file
21
src/Anno.EngineData/IPlugsConfigurationBootstrap.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件启动配置
|
||||
/// </summary>
|
||||
public interface IPlugsConfigurationBootstrap
|
||||
{
|
||||
/// <summary>
|
||||
///IOC之前
|
||||
/// </summary>
|
||||
void PreConfigurationBootstrap();
|
||||
/// <summary>
|
||||
/// 插件启动配置
|
||||
/// </summary>
|
||||
void ConfigurationBootstrap();
|
||||
}
|
||||
}
|
||||
22
src/Anno.EngineData/IRpcConnector.cs
Normal file
22
src/Anno.EngineData/IRpcConnector.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
public interface IRpcConnector
|
||||
{
|
||||
string BrokerDns(Dictionary<string, string> input);
|
||||
Task<string> BrokerDnsAsync(Dictionary<string, string> input, string nickName);
|
||||
Task<string> BrokerDnsAsync(Dictionary<string, string> input);
|
||||
void SetDefaultConfiguration(string appName, string centerAddress, int port = 6660, bool traceOnOff = true);
|
||||
/// <summary>
|
||||
/// 设置连接池信息
|
||||
/// </summary>
|
||||
/// <param name="maxActive"></param>
|
||||
/// <param name="minIdle"></param>
|
||||
/// <param name="maxIdle"></param>
|
||||
void SetDefaultConnectionPool(int maxActive, int minIdle, int maxIdle);
|
||||
}
|
||||
}
|
||||
69
src/Anno.EngineData/InvokeEngine.cs
Normal file
69
src/Anno.EngineData/InvokeEngine.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Anno.EngineData;
|
||||
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
using Anno.Const.Enum;
|
||||
public abstract class InvokeEngine
|
||||
{
|
||||
private static readonly IRpcConnector rpcConnector = Loader.IocLoader.Resolve<IRpcConnector>();
|
||||
/// <summary>
|
||||
/// 集群--全局调用处理器
|
||||
/// </summary>
|
||||
/// <param name="channel">管道Anno.Logic(Anno.Plugs.LogicService)</param>
|
||||
/// <param name="router">路由Platform(PlatformModule)</param>
|
||||
/// <param name="method">方法ChangePwd</param>
|
||||
/// <param name="response">发送内容</param>
|
||||
/// <returns></returns>
|
||||
public static string InvokeProcessor(string channel, string router, string method, Dictionary<string, string> response)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(channel) || string.IsNullOrWhiteSpace(router) ||
|
||||
string.IsNullOrWhiteSpace(method))
|
||||
{
|
||||
throw new AnnoInvokeEngineException(AnnoInvokeEngineException.AnnoInvokeEngineExceptionType.Argument,"【管道、路由、方法】三个参数为必输参数!");
|
||||
}
|
||||
if (response.ContainsKey(Eng.NAMESPACE))
|
||||
{
|
||||
response[Eng.NAMESPACE] = channel;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Add(Eng.NAMESPACE, channel);
|
||||
}
|
||||
if (response.ContainsKey(Eng.CLASS))
|
||||
{
|
||||
response[Eng.CLASS] = router;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Add(Eng.CLASS, router);
|
||||
}
|
||||
if (response.ContainsKey(Eng.METHOD))
|
||||
{
|
||||
response[Eng.METHOD] = method;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Add(Eng.METHOD, method);
|
||||
}
|
||||
return rpcConnector.BrokerDns(response);
|
||||
}
|
||||
/// <summary>
|
||||
/// 集群--全局调用处理器---异步
|
||||
/// </summary>
|
||||
/// <param name="channel">管道Anno.Logic(Anno.Plugs.LogicService)</param>
|
||||
/// <param name="router">路由Platform(PlatformModule)</param>
|
||||
/// <param name="method">方法ChangePwd</param>
|
||||
/// <param name="response">发送内容</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> InvokeProcessorAsync(string channel, string router, string method,
|
||||
Dictionary<string, string> response)
|
||||
{
|
||||
return await Task.Run(() => InvokeProcessor(channel, router, method, response));
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/Anno.EngineData/Routing/RoutInfo.cs
Normal file
26
src/Anno.EngineData/Routing/RoutInfo.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Anno.EngineData.Cache;
|
||||
using Anno.EngineData.Filters;
|
||||
|
||||
namespace Anno.EngineData.Routing
|
||||
{
|
||||
public class RoutInfo
|
||||
{
|
||||
private MethodInfo methodInfo;
|
||||
|
||||
public Type RoutModuleType { get; set; }
|
||||
|
||||
public MethodInfo RoutMethod
|
||||
{
|
||||
get { return methodInfo; }
|
||||
set { methodInfo = value; }
|
||||
}
|
||||
public List<IAuthorizationFilter> AuthorizationFilters { get; set; } = new List<IAuthorizationFilter>();
|
||||
public List<IActionFilter> ActionFilters { get; set; } = new List<IActionFilter>();
|
||||
public List<IExceptionFilter> ExceptionFilters { get; set; } = new List<IExceptionFilter>();
|
||||
public List<ICacheMiddleware> CacheMiddleware { get; set; } = new List<ICacheMiddleware>();
|
||||
}
|
||||
}
|
||||
51
src/Anno.EngineData/Routing/Routing.cs
Normal file
51
src/Anno.EngineData/Routing/Routing.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Collections.Concurrent;
|
||||
using Anno.EngineData.Filters;
|
||||
using System.Linq;
|
||||
using Anno.EngineData.Cache;
|
||||
|
||||
namespace Anno.EngineData.Routing
|
||||
{
|
||||
public static class Routing
|
||||
{
|
||||
internal static List<IActionFilter> GlobalActionFilters { get; private set; } = new List<IActionFilter>();
|
||||
internal static List<IExceptionFilter> GlobalExceptionFilters { get; private set; } = new List<IExceptionFilter>();
|
||||
internal static List<IAuthorizationFilter> GlobalAuthorizationFilters { get; private set; } = new List<IAuthorizationFilter>();
|
||||
internal static List<ICacheMiddleware> GlobalCacheMiddleware { get; set; } = new List<ICacheMiddleware>();
|
||||
|
||||
#region 全局过滤器
|
||||
public static bool AddFilter(IFilterMetadata metadata)
|
||||
{
|
||||
bool success = false;
|
||||
if (metadata.GetType().GetInterface("IActionFilter") != null)
|
||||
{
|
||||
if (!GlobalActionFilters.Contains(metadata))
|
||||
{
|
||||
GlobalActionFilters.Add(metadata as IActionFilter);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
if (metadata.GetType().GetInterface("IExceptionFilter") != null)
|
||||
{
|
||||
if (!GlobalExceptionFilters.Contains(metadata))
|
||||
{
|
||||
GlobalExceptionFilters.Add(metadata as IExceptionFilter);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
if (metadata.GetType().GetInterface("IAuthorizationFilter") != null)
|
||||
{
|
||||
if (!GlobalAuthorizationFilters.Contains(metadata))
|
||||
{
|
||||
GlobalAuthorizationFilters.Add(metadata as IAuthorizationFilter);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endregion
|
||||
public static ConcurrentDictionary<string, RoutInfo> Router { get; set; } = new ConcurrentDictionary<string, RoutInfo>();
|
||||
}
|
||||
}
|
||||
40
src/Anno.EngineData/SysInfo/AnnoDrives.cs
Normal file
40
src/Anno.EngineData/SysInfo/AnnoDrives.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.SysInfo
|
||||
{
|
||||
public class AnnoDrives
|
||||
{
|
||||
public static List<AnnoDrive> GetDrivesInfo()
|
||||
{
|
||||
List<AnnoDrive> drives = new List<AnnoDrive>();
|
||||
foreach (var d in DriveInfo.GetDrives())
|
||||
{
|
||||
if (d.DriveType == DriveType.CDRom)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (d.TotalSize >= 1024 * 1024)//磁盘大于1M
|
||||
{
|
||||
double freeSpace = 0;
|
||||
if (d.TotalFreeSpace > 0)
|
||||
{
|
||||
freeSpace = Math.Round(d.TotalFreeSpace / 1024 / 1024 / 1024.000, 3);
|
||||
}
|
||||
var totalSpace = Math.Round(d.TotalSize / 1024 / 1024 / 1024.000, 3);
|
||||
drives.Add(new AnnoDrive() { Name = d.Name.Replace(":\\", ":"), Total = totalSpace, Free = freeSpace });
|
||||
}
|
||||
}
|
||||
return drives;
|
||||
}
|
||||
}
|
||||
|
||||
public class AnnoDrive
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public double Total { get; set; }
|
||||
public double Free { get; set; }
|
||||
}
|
||||
}
|
||||
13
src/Anno.EngineData/SysInfo/MemoryMetrics.cs
Normal file
13
src/Anno.EngineData/SysInfo/MemoryMetrics.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.SysInfo
|
||||
{
|
||||
public class MemoryMetrics
|
||||
{
|
||||
public double Total;
|
||||
public double Used;
|
||||
public double Free;
|
||||
}
|
||||
}
|
||||
86
src/Anno.EngineData/SysInfo/MemoryMetricsClient.cs
Normal file
86
src/Anno.EngineData/SysInfo/MemoryMetricsClient.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.SysInfo
|
||||
{
|
||||
public class MemoryMetricsClient
|
||||
{
|
||||
public MemoryMetrics GetMetrics()
|
||||
{
|
||||
if (IsUnix())
|
||||
{
|
||||
return GetUnixMetrics();
|
||||
}
|
||||
|
||||
return GetWindowsMetrics();
|
||||
}
|
||||
|
||||
private bool IsUnix()
|
||||
{
|
||||
#if NETSTANDARD
|
||||
var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ||
|
||||
RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
#else
|
||||
var isUnix = Environment.OSVersion.Platform.ToString() == "Unix" ||
|
||||
Environment.OSVersion.Platform.ToString() == "MacOSX";
|
||||
#endif
|
||||
return isUnix;
|
||||
}
|
||||
|
||||
private MemoryMetrics GetWindowsMetrics()
|
||||
{
|
||||
var output = "";
|
||||
|
||||
var info = new ProcessStartInfo();
|
||||
info.FileName = "wmic";
|
||||
info.Arguments = "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value";
|
||||
info.RedirectStandardOutput = true;
|
||||
|
||||
using (var process = Process.Start(info))
|
||||
{
|
||||
output = process.StandardOutput.ReadToEnd();
|
||||
}
|
||||
|
||||
var lines = output.Trim().Split("\n".ToCharArray());
|
||||
var freeMemoryParts = lines[0].Split("=".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
var totalMemoryParts = lines[1].Split("=".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var metrics = new MemoryMetrics();
|
||||
metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
|
||||
metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);
|
||||
metrics.Used = metrics.Total - metrics.Free;
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
private MemoryMetrics GetUnixMetrics()
|
||||
{
|
||||
var output = "";
|
||||
|
||||
var info = new ProcessStartInfo("free -m");
|
||||
info.FileName = "/bin/bash";
|
||||
info.Arguments = "-c \"free -m\"";
|
||||
info.RedirectStandardOutput = true;
|
||||
|
||||
using (var process = Process.Start(info))
|
||||
{
|
||||
output = process.StandardOutput.ReadToEnd();
|
||||
Console.WriteLine(output);
|
||||
}
|
||||
|
||||
var lines = output.Split("\n".ToCharArray());
|
||||
var memory = lines[1].Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var metrics = new MemoryMetrics();
|
||||
metrics.Total = double.Parse(memory[1]);
|
||||
//metrics.Used = double.Parse(memory[2]);
|
||||
metrics.Free = double.Parse(memory[3]);
|
||||
metrics.Used = metrics.Total - metrics.Free;//包括 buff/Caches
|
||||
|
||||
return metrics;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/Anno.EngineData/SysInfo/RunTimeWatch.cs
Normal file
35
src/Anno.EngineData/SysInfo/RunTimeWatch.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.SysInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 记录程序运行时长
|
||||
/// </summary>
|
||||
public class RunTimeWatch
|
||||
{
|
||||
static RunTimeWatch()
|
||||
{
|
||||
mWatch = new System.Diagnostics.Stopwatch();
|
||||
StartTime = DateTime.Now;
|
||||
mWatch.Start();
|
||||
}
|
||||
|
||||
private static readonly System.Diagnostics.Stopwatch mWatch;
|
||||
/// <summary>
|
||||
/// 启动时间
|
||||
/// </summary>
|
||||
public static DateTime StartTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取程序运行时长
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
public static long GetRunTimeMilliseconds()
|
||||
{
|
||||
return mWatch.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
141
src/Anno.EngineData/SysInfo/UseSysInfoWatch.cs
Normal file
141
src/Anno.EngineData/SysInfo/UseSysInfoWatch.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData.SysInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用系统资源信息
|
||||
/// </summary>
|
||||
public class UseSysInfoWatch
|
||||
{
|
||||
MemoryMetricsClient memoryMetricsClient = new MemoryMetricsClient();
|
||||
private int mProcessorCount;
|
||||
public UseSysInfoWatch()
|
||||
{
|
||||
mProcessorCount = Environment.ProcessorCount;
|
||||
_mLastTime = RunTimeWatch.GetRunTimeMilliseconds();
|
||||
_mCpuMaxTime = mProcessorCount * 1000;
|
||||
mProcess = Process.GetCurrentProcess();
|
||||
_mLastTotalProcessorTime = mProcess.TotalProcessorTime.Milliseconds;
|
||||
}
|
||||
|
||||
private readonly System.Diagnostics.Process mProcess;
|
||||
|
||||
private readonly long _mCpuMaxTime;
|
||||
|
||||
|
||||
private long _mLastTime;
|
||||
|
||||
private double _mLastTotalProcessorTime;
|
||||
|
||||
private ServerStatus _mInfo = new ServerStatus();
|
||||
|
||||
private long _mLastGetTime;
|
||||
|
||||
private int _mGetStatus = 0;
|
||||
/// <summary>
|
||||
/// 获取服务状态
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
public ServerStatus GetServerStatus()
|
||||
{
|
||||
if (RunTimeWatch.GetRunTimeMilliseconds() - _mLastGetTime > 1000)
|
||||
{
|
||||
if (System.Threading.Interlocked.CompareExchange(ref _mGetStatus, 1, 0) == 0)
|
||||
{
|
||||
_mLastGetTime = RunTimeWatch.GetRunTimeMilliseconds();
|
||||
ServerStatus result = new ServerStatus();
|
||||
TimeSpan ts = (DateTime.Now - RunTimeWatch.StartTime);
|
||||
result.RunTime = $"{(long)ts.Days}:{(long)ts.Hours}:{(long)ts.Minutes}:{(long)ts.Seconds}";
|
||||
|
||||
long time = RunTimeWatch.GetRunTimeMilliseconds();
|
||||
double second = (double)(time - _mLastTime) / 1000d;
|
||||
_mLastTime = time;
|
||||
double cpuTime = mProcess.TotalProcessorTime.TotalMilliseconds;
|
||||
long cpuFullTime = (long)(second * _mCpuMaxTime);
|
||||
double useTime = cpuTime - _mLastTotalProcessorTime;
|
||||
_mLastTotalProcessorTime = cpuTime;
|
||||
result.Cpu = (int)((useTime / cpuFullTime) * 10000) / 100d;
|
||||
|
||||
if (result.Cpu > 100)
|
||||
result.Cpu = 100;
|
||||
if (result.Cpu < 0)
|
||||
result.Cpu = 0;
|
||||
result.Memory = (Environment.WorkingSet / 1024) / 1024;
|
||||
_mInfo = result;
|
||||
System.Threading.Interlocked.Exchange(ref _mGetStatus, 0);
|
||||
}
|
||||
}
|
||||
var metrics = memoryMetricsClient.GetMetrics();
|
||||
_mInfo.MemoryTotal = metrics.Total;
|
||||
_mInfo.MemoryTotalUse = metrics.Used;
|
||||
_mInfo.CpuTotalUse = GetCpuTotalUse();
|
||||
_mInfo.Drives = AnnoDrives.GetDrivesInfo();
|
||||
if (_mInfo.Cpu > _mInfo.CpuTotalUse)
|
||||
_mInfo.CpuTotalUse = _mInfo.Cpu;
|
||||
return _mInfo;
|
||||
}
|
||||
|
||||
private double GetCpuTotalUse()
|
||||
{
|
||||
var processes = Process.GetProcesses().Where(p => p.ProcessName != "Idle");
|
||||
int cpuFullTime = 200;
|
||||
|
||||
double cpuTimeFirst = 0;
|
||||
double cpuTimeSecond = 0;
|
||||
foreach (var process in processes)
|
||||
{
|
||||
try
|
||||
{
|
||||
cpuTimeFirst += process.TotalProcessorTime.TotalMilliseconds;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
System.Threading.Thread.Sleep(cpuFullTime);
|
||||
foreach (var process in processes)
|
||||
{
|
||||
try
|
||||
{
|
||||
cpuTimeSecond += process.TotalProcessorTime.TotalMilliseconds;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
double useTime = cpuTimeSecond - cpuTimeFirst;
|
||||
var cpuUse = (useTime / (cpuFullTime * mProcessorCount)) * 100d;
|
||||
if (cpuUse > 100)
|
||||
cpuUse = 100;
|
||||
if (cpuUse < 0)
|
||||
cpuUse = 0;
|
||||
return cpuUse;
|
||||
}
|
||||
public class ServerStatus
|
||||
{
|
||||
public ServerStatus()
|
||||
{
|
||||
}
|
||||
public string RunTime { get; set; }
|
||||
public DateTime CurrentTime { get; set; } = DateTime.Now;
|
||||
public long Memory { get; set; }
|
||||
public double Cpu { get; set; }
|
||||
public string Tag { get; set; }
|
||||
|
||||
public double MemoryTotal { get; set; }
|
||||
public double MemoryTotalUse { get; set; }
|
||||
public double CpuTotalUse { get; set; }
|
||||
|
||||
public List<AnnoDrive> Drives { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
63
src/Anno.EngineData/ValidatetionExtension.cs
Normal file
63
src/Anno.EngineData/ValidatetionExtension.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Anno.EngineData
|
||||
{
|
||||
public static class ValidatetionExtension
|
||||
{
|
||||
public static ValidResult IsValid<T>(this T value) where T : class
|
||||
{
|
||||
ValidResult result = new ValidResult();
|
||||
try
|
||||
{
|
||||
var validationContext = new ValidationContext(value);
|
||||
var results = new List<ValidationResult>();
|
||||
var isValid = Validator.TryValidateObject(value, validationContext, results, true);
|
||||
|
||||
if (!isValid)
|
||||
{
|
||||
result.IsVaild = false;
|
||||
result.ErrorMembers = new List<ErrorMember>();
|
||||
foreach (var item in results)
|
||||
{
|
||||
result.ErrorMembers.Add(new ErrorMember()
|
||||
{
|
||||
ErrorMessage = item.ErrorMessage,
|
||||
ErrorMemberName = string.Join(",", item.MemberNames)
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.IsVaild = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsVaild = false;
|
||||
result.ErrorMembers = new List<ErrorMember>();
|
||||
result.ErrorMembers.Add(new ErrorMember()
|
||||
{
|
||||
ErrorMessage = ex.Message,
|
||||
ErrorMemberName = "Internal error"
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public struct ValidResult
|
||||
{
|
||||
public List<ErrorMember> ErrorMembers { get; set; }
|
||||
public bool IsVaild { get; set; }
|
||||
}
|
||||
|
||||
public class ErrorMember
|
||||
{
|
||||
public string ErrorMessage { get; set; }
|
||||
public string ErrorMemberName { get; set; }
|
||||
}
|
||||
}
|
||||
26
src/Anno.Loader/Anno.Loader.csproj
Normal file
26
src/Anno.Loader/Anno.Loader.csproj
Normal file
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTfms);net461</TargetFrameworks>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>$(Version)</Version>
|
||||
<Authors>Du yanming</Authors>
|
||||
<Company>Du yanming</Company>
|
||||
<Product>Anno IOC DI</Product>
|
||||
<Description>分布式开发框架 依赖注入</Description>
|
||||
<PackageProjectUrl>https://github.com/duyanming/Viper</PackageProjectUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
|
||||
<PackageReference Include="Autofac" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == '$(StandardTfms)'">
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Anno.Const\Anno.Const.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
69
src/Anno.Loader/AutofacModule.cs
Normal file
69
src/Anno.Loader/AutofacModule.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Anno.Loader
|
||||
{
|
||||
public class AutofacModule : Autofac.Module
|
||||
{
|
||||
//注意以下写法
|
||||
//builder.RegisterType<GuidTransientAnnoService>().As<IGuidTransientAnnoService>();
|
||||
//builder.RegisterType<GuidScopedAnnoService>().As<IGuidScopedAnnoService>().InstancePerLifetimeScope();
|
||||
//builder.RegisterType<GuidSingletonAnnoService>().As<IGuidSingletonAnnoService>().SingleInstance();
|
||||
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
// The generic ILogger<TCategoryName> service was added to the ServiceCollection by ASP.NET Core.
|
||||
// It was then registered with Autofac using the Populate method in ConfigureServices.
|
||||
|
||||
//builder.Register(c => new ValuesService(c.Resolve<ILogger<ValuesService>>()))
|
||||
// .As<IValuesService>()
|
||||
// .InstancePerLifetimeScope();
|
||||
// builder.RegisterType<BaseRepository>().As<IBaseRepository>();
|
||||
Const.AppSettings.IocDll.Distinct().ToList().ForEach(d =>
|
||||
{
|
||||
RegisterAssembly(builder, Const.Assemblys.Dic[d]);
|
||||
});
|
||||
foreach (var assembly in Const.Assemblys.DependedTypes)
|
||||
{
|
||||
RegisterAssembly(builder, assembly);
|
||||
}
|
||||
}
|
||||
private void RegisterAssembly(ContainerBuilder builder, Assembly assembly)
|
||||
{
|
||||
assembly.GetTypes().Where(x => x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract && !x.GetTypeInfo().IsInterface).ToList().ForEach(
|
||||
t =>
|
||||
{
|
||||
var interfaces = t.GetInterfaces();
|
||||
if (IsAssignableFrom(t, "Anno.EngineData.BaseModule")
|
||||
|| interfaces.ToList().Exists(i => i.Name == "IFilterMetadata")
|
||||
|| interfaces.Length <= 0)
|
||||
{
|
||||
builder.RegisterType(t);
|
||||
}
|
||||
else if (!interfaces.ToList().Exists(i => i.Name == "IEntity"))
|
||||
{
|
||||
builder.RegisterType(t).As(t.GetInterfaces());
|
||||
}
|
||||
});
|
||||
}
|
||||
internal static bool IsAssignableFrom(Type type, string baseTypeFullName)
|
||||
{
|
||||
bool success = false;
|
||||
if (type == null)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
else if (type.FullName == baseTypeFullName)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
else if (type.BaseType != null)
|
||||
{
|
||||
success = IsAssignableFrom(type.BaseType, baseTypeFullName);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user