新建服务端项目Stardust.Server,原Stardust作为基础组件,供业务系统引用

This commit is contained in:
大石头 2019-03-20 20:49:23 +08:00
parent 72d95820d2
commit 528dc777e7
11 changed files with 391 additions and 31 deletions

View File

@ -6,7 +6,7 @@
<Description>星尘,轻量级服务框架。远程方法调用,服务自动注册和发现,负载均衡,动态伸缩,故障转移,性能监控。</Description>
<Copyright>版权所有(C) 新生命开发团队 2019</Copyright>
<Company>新生命开发团队</Company>
<FileVersion>1.0.2019.0101</FileVersion>
<FileVersion>1.0.2019.0320</FileVersion>
<AssemblyVersion>1.0.*</AssemblyVersion>
<Deterministic>false</Deterministic>
</PropertyGroup>

114
Stardust.Server/Program.cs Normal file
View File

@ -0,0 +1,114 @@
using System;
using System.Net;
using NewLife;
using NewLife.Agent;
using NewLife.Log;
using NewLife.Net;
using NewLife.Remoting;
using NewLife.Threading;
using Stardust.Data;
namespace Stardust.Server
{
class Program
{
static void Main(String[] args) => new MyService().Main();
}
/// <summary>服务类。名字可以自定义</summary>
class MyService : AgentServiceBase<MyService>
{
/// <summary>是否使用线程池调度。false表示禁用线程池改用Agent线程</summary>
public Boolean Pooling { get; set; } = true;
public MyService()
{
ServiceName = "Stardust";
ThreadPoolX.QueueUserWorkItem(() =>
{
var n = App.Meta.Count;
AppStat.Meta.Session.Dal.Db.ShowSQL = false;
var set2 = XCode.Setting.Current;
if (set2.IsNew)
{
set2.Debug = true;
set2.ShowSQL = false;
set2.TraceSQLTime = 3000;
set2.SQLiteDbPath = @"..\Data";
set2.Save();
}
});
// 注册菜单,在控制台菜单中按 t 可以执行Test函数主要用于临时处理数据
AddMenu('t', "数据测试", Test);
}
ApiServer _Server;
private void Init()
{
var sc = _Server;
if (sc == null)
{
var set = Setting.Current;
sc = new ApiServer(set.Port)
{
Log = XTrace.Log
};
if (set.Debug)
{
var ns = sc.EnsureCreate() as NetServer;
ns.Log = XTrace.Log;
#if DEBUG
ns.LogSend = true;
ns.LogReceive = true;
sc.EncoderLog = XTrace.Log;
#endif
}
// 注册服务
sc.Register<StarService>();
StarService.Log = XTrace.Log;
StarService.Local = new IPEndPoint(NetHelper.MyIP(), set.Port);
sc.Start();
_Server = sc;
}
}
/// <summary>服务启动</summary>
/// <remarks>
/// 安装Windows服务后服务启动会执行一次该方法。
/// 控制台菜单按5进入循环调试也会执行该方法。
/// </remarks>
protected override void StartWork(String reason)
{
Init();
base.StartWork(reason);
}
/// <summary>服务停止</summary>
/// <remarks>
/// 安装Windows服务后服务停止会执行该方法。
/// 控制台菜单按5进入循环调试任意键结束时也会执行该方法。
/// </remarks>
protected override void StopWork(String reason)
{
base.StopWork(reason);
_Server.TryDispose();
_Server = null;
}
/// <summary>数据测试菜单t</summary>
public void Test()
{
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.ComponentModel;
using NewLife.Xml;
namespace Stardust.Server
{
/// <summary>配置</summary>
[XmlConfigFile("Config/Stardust.config", 15000)]
public class Setting : XmlConfig<Setting>
{
#region
/// <summary>调试开关。默认true</summary>
[Description("调试开关。默认true")]
public Boolean Debug { get; set; } = true;
/// <summary>服务端口。默认6666</summary>
[Description("服务端口。默认6666")]
public Int32 Port { get; set; } = 6666;
#endregion
#region
/// <summary>实例化</summary>
public Setting()
{
}
#endregion
}
}

View File

@ -0,0 +1,195 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using NewLife.Log;
using NewLife.Net;
using NewLife.Remoting;
using Stardust.Data;
namespace Stardust.Server
{
[Api(null)]
public class StarService : IApi, IActionFilter
{
#region
/// <summary>本地节点</summary>
public static EndPoint Local { get; set; }
#endregion
#region
public IApiSession Session { get; set; }
/// <summary>
/// 传入应用名和密钥登陆,
/// 返回应用名和应用显示名
/// </summary>
/// <param name="user">应用名</param>
/// <param name="pass"></param>
/// <returns></returns>
[Api(nameof(Login))]
public Object Login(String user, String pass)
{
if (user.IsNullOrEmpty()) throw new ArgumentNullException(nameof(user));
if (pass.IsNullOrEmpty()) throw new ArgumentNullException(nameof(pass));
var ns = Session as INetSession;
var ip = ns.Remote.Host;
var ps = ControllerContext.Current.Parameters;
WriteLog("[{0}]从[{1}]登录", user, ns.Remote);
// 找应用
var app = App.FindByName(user);
if (app == null || app.Secret.IsNullOrEmpty())
{
if (app == null) app = new App();
if (app.ID == 0)
{
app.Name = user;
//app.Secret = pass;
app.CreateIP = ip;
app.CreateTime = DateTime.Now;
app.Enable = true;
}
var name = ps["name"] + "";
if (!name.IsNullOrEmpty()) app.DisplayName = name;
app.UpdateIP = ip;
app.UpdateTime = DateTime.Now;
app.Save();
}
if (!app.Enable) throw new Exception("已禁用!");
// 核对密码
if (!app.Secret.IsNullOrEmpty())
{
var pass2 = app.Secret.MD5();
if (pass != pass2) throw new Exception("密码错误!");
}
// 应用上线
CreateOnline(app, ns, ps);
app.LastIP = ip;
app.LastLogin = DateTime.Now;
app.Save();
// 记录当前用户
Session["App"] = app;
return new
{
app.Name,
app.DisplayName,
};
}
void IActionFilter.OnActionExecuting(ControllerContext filterContext)
{
var act = filterContext.ActionName;
if (act == nameof(Login)) return;
if (Session["App"] is App app)
{
var online = GetOnline(app, Session as INetSession);
online.UpdateTime = DateTime.Now;
online.SaveAsync();
}
else
{
var ns = Session as INetSession;
throw new ApiException(401, "{0}未登录!不能执行{1}".F(ns.Remote, act));
}
}
void IActionFilter.OnActionExecuted(ControllerContext filterContext)
{
var ex = filterContext.Exception;
if (ex != null && !filterContext.ExceptionHandled)
{
// 显示错误
if (ex is ApiException)
XTrace.Log.Error(ex.Message);
else
XTrace.WriteException(ex);
}
}
#endregion
#region
/// <summary>报告服务列表</summary>
/// <param name="services"></param>
/// <returns></returns>
[Api(nameof(Report))]
public Boolean Report(String[] services)
{
return false;
}
#endregion
#region 线
AppOnline CreateOnline(IApp app, INetSession ns, IDictionary<String, Object> ps)
{
var ip = ns.Remote.Host;
var machine = ps["machine"] + "";
var pid = ps["processid"].ToInt();
var ver = ps["version"] + "";
var compile = ps["compile"].ToDateTime();
var online = GetOnline(app, ns);
// 客户端特性
online.Client = $"{(ip.IsNullOrEmpty() ? machine : ip)}@{pid}";
online.Name = machine;
online.Version = ver;
online.Compile = compile;
// 服务器特性
pid = Process.GetCurrentProcess().Id;
online.Server = Local + "@" + pid;
online.Save();
// 真正的用户
Session["AppOnline"] = online;
// 下线
ns.OnDisposed += (s, e) => online.Delete();
// 版本和编译时间
if (app.Version.IsNullOrEmpty() || app.Version.CompareTo(ver) < 0) app.Version = ver;
if (app.Compile.Year < 2000 || app.Compile < compile) app.Compile = compile;
return online;
}
AppOnline GetOnline(IApp app, INetSession ns)
{
if (Session["AppOnline"] is AppOnline online) return online;
var ip = ns.Remote.Host;
var ins = ns.Remote.EndPoint + "";
online = AppOnline.FindBySession(ins) ?? new AppOnline { CreateIP = ip };
online.AppID = app.ID;
online.Session = ins;
return online;
}
#endregion
#region
/// <summary>日志</summary>
public static ILog Log { get; set; }
/// <summary>写日志</summary>
/// <param name="format"></param>
/// <param name="args"></param>
public static void WriteLog(String format, params Object[] args) => Log?.Info(format, args);
#endregion
}
}

View File

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyTitle>星尘</AssemblyTitle>
<Description>星尘,轻量级服务框架。远程方法调用,服务自动注册和发现,负载均衡,动态伸缩,故障转移,性能监控。</Description>
<Copyright>版权所有(C) 新生命开发团队 2019</Copyright>
<Company>新生命开发团队</Company>
<FileVersion>1.0.2019.0320</FileVersion>
<AssemblyVersion>1.0.*</AssemblyVersion>
<Deterministic>false</Deterministic>
<OutputPath>..\Bin</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Stardust.Data\Stardust.Data.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="NewLife.Agent">
<HintPath>..\DLL20\NewLife.Agent.dll</HintPath>
</Reference>
<Reference Include="NewLife.Core">
<HintPath>..\DLL20\NewLife.Core.dll</HintPath>
</Reference>
<Reference Include="XCode">
<HintPath>..\DLL20\XCode.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -1,12 +1,5 @@
using System;
using System.Net;
using NewLife;
using NewLife.Agent;
using NewLife.Log;
using NewLife.Net;
using NewLife.Remoting;
using NewLife.Threading;
using Stardust.Data;
namespace Stardust
{

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using NewLife.Log;
using NewLife.Net;

View File

@ -1,36 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
<AssemblyTitle>星尘</AssemblyTitle>
<Description>星尘,轻量级服务框架。远程方法调用,服务自动注册和发现,负载均衡,动态伸缩,故障转移,性能监控。</Description>
<Copyright>版权所有(C) 新生命开发团队 2019</Copyright>
<Company>新生命开发团队</Company>
<FileVersion>1.0.2019.0101</FileVersion>
<FileVersion>1.0.2019.0320</FileVersion>
<AssemblyVersion>1.0.*</AssemblyVersion>
<Deterministic>false</Deterministic>
<OutputPath>..\Bin</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.5.0" />
<Compile Remove="Program.cs" />
<Compile Remove="Setting.cs" />
<Compile Remove="StarService.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Stardust.Data\Stardust.Data.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="NewLife.Agent">
<HintPath>..\DLL20\NewLife.Agent.dll</HintPath>
</Reference>
<Reference Include="NewLife.Core">
<HintPath>..\DLL20\NewLife.Core.dll</HintPath>
</Reference>
<Reference Include="XCode">
<HintPath>..\DLL20\XCode.dll</HintPath>
</Reference>
<PackageReference Include="NewLife.Core" Version="8.1.2019.314" />
</ItemGroup>
</Project>

View File

@ -4,8 +4,8 @@ using System.Threading;
using NewLife.Log;
using NewLife.Net;
using NewLife.Remoting;
using Stardust;
using Setting = Stardust.Setting;
using Stardust.Server;
using Setting = Stardust.Server.Setting;
namespace Test
{

View File

@ -9,6 +9,7 @@
<ItemGroup>
<ProjectReference Include="..\Stardust.Data\Stardust.Data.csproj" />
<ProjectReference Include="..\Stardust.Server\Stardust.Server.csproj" />
<ProjectReference Include="..\Stardust\Stardust.csproj" />
</ItemGroup>

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.168
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stardust", "Stardust\Stardust.csproj", "{AADBD913-749C-467E-A63F-C118C4C82351}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stardust", "Stardust\Stardust.csproj", "{AADBD913-749C-467E-A63F-C118C4C82351}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stardust.Web", "Stardust.Web\Stardust.Web.csproj", "{25331DEF-FEE3-44D5-A4E9-864078441F71}"
EndProject
@ -16,7 +16,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stardust.Data", "Stardust.D
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stardust.WebFx", "Stardust.WebFx\Stardust.WebFx.csproj", "{A9E0597C-E818-4B33-8AC3-BE134D68B78E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{3B87711E-FF90-470B-A429-CFDF3B9B1F5F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{3B87711E-FF90-470B-A429-CFDF3B9B1F5F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stardust.Server", "Stardust.Server\Stardust.Server.csproj", "{73B28F07-E99F-45A8-B9A0-90E7BAC133A3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -44,6 +46,10 @@ Global
{3B87711E-FF90-470B-A429-CFDF3B9B1F5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B87711E-FF90-470B-A429-CFDF3B9B1F5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B87711E-FF90-470B-A429-CFDF3B9B1F5F}.Release|Any CPU.Build.0 = Release|Any CPU
{73B28F07-E99F-45A8-B9A0-90E7BAC133A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73B28F07-E99F-45A8-B9A0-90E7BAC133A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73B28F07-E99F-45A8-B9A0-90E7BAC133A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73B28F07-E99F-45A8-B9A0-90E7BAC133A3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE