static void Main() { VirtualRoot.SetOut(new ConsoleOut()); NTMinerConsole.MainUiOk(); NTMinerConsole.DisbleQuickEditMode(); DevMode.SetDevMode(); Windows.ConsoleHandler.Register(Exit); try { bool mutexCreated; try { // 锁名称上带上本节点的端口号,从而允许一个服务器上运行多个WebApiServer节点,这在软升级服务端程序时有用。 // 升级WebApiServer程序的时候步骤是: // 1,在另一个端口启动新版本的程序; // 2,让Widnows将来自旧端口的所有tcp请求转发到新端口; // 3,退出旧版本的程序并更新到新版本; // 4,删除第2步添加的Windows的端口转发; // 5,退出第1步运行的节点; // TODO:实现软升级策略 _sMutexApp = new Mutex(true, $"NTMinerServicesMutex{ServerRoot.HostConfig.GetServerPort().ToString()}", out mutexCreated); } catch { mutexCreated = false; } if (mutexCreated) { try { // 用本节点的地址作为队列名,消费消息时根据路由键区分消息类型 string queue = $"{nameof(ServerAppType.WebApiServer)}.{ServerRoot.HostConfig.ThisServerAddress}"; string durableQueue = queue + MqKeyword.DurableQueueEndsWith; string wsBreathQueue = queue + MqKeyword.WsBreathQueueEndsWith; AbstractMqMessagePath[] mqMessagePaths = new AbstractMqMessagePath[] { new UserMqMessagePath(durableQueue), new CalcConfigMqMessagePath(queue), new MinerClientMqMessagePath(queue), new WsBreathMqMessagePath(wsBreathQueue), new OperationMqMessagePath(queue), new MqCountMqMessagePath(queue), new ClientTestIdMqMessagePath(queue) }; if (!MqRedis.Create(ServerAppType.WebApiServer, mqMessagePaths, out IMqRedis mqRedis)) { NTMinerConsole.UserError("启动失败,无法继续,因为服务器上下文创建失败"); return; } Console.Title = $"{nameof(ServerAppType.WebApiServer)}_{ServerRoot.HostConfig.ThisServerAddress}"; // 阿里云OSS坑爹比七牛Kodo贵一半 CloudFileUrlGenerater = new AliCloudOSSFileUrlGenerater(); IRedis redis = mqRedis; IMq mq = mqRedis; AdminMqSender = new AdminMqSender(mq); ClientTestIdDataRedis = new ClientTestIdDataRedis(redis); var minerClientMqSender = new MinerClientMqSender(mq); var userMqSender = new UserMqSender(mq); var calcConfigMqSender = new CalcConfigMqSender(mq); var minerRedis = new MinerDataRedis(redis); var clientActiveOnRedis = new ClientActiveOnRedis(redis); var speedDataRedis = new SpeedDataRedis(redis); var userRedis = new UserDataRedis(redis); var captchaRedis = new CaptchaDataRedis(redis); var calcConfigRedis = new CalcConfigDataRedis(redis); MqCountSet = new MqCountSet(); WsServerNodeRedis = new WsServerNodeRedis(redis); WsServerNodeAddressSet = new WsServerNodeAddressSet(WsServerNodeRedis); UserSet = new UserSet(userRedis, userMqSender); UserAppSettingSet = new UserAppSettingSet(); CaptchaSet = new CaptchaSet(captchaRedis); CalcConfigSet = new CalcConfigSet(calcConfigRedis, calcConfigMqSender); NTMinerWalletSet = new NTMinerWalletSet(); GpuNameSet = new GpuNameSet(); ClientDataSet clientDataSet = new ClientDataSet(minerRedis, clientActiveOnRedis, speedDataRedis, minerClientMqSender); ClientDataSet = clientDataSet; var operationMqSender = new OperationMqSender(mq); MineWorkSet = new UserMineWorkSet(operationMqSender); MinerGroupSet = new UserMinerGroupSet(); NTMinerFileSet = new NTMinerFileSet(); OverClockDataSet = new OverClockDataSet(); KernelOutputKeywordSet = new KernelOutputKeywordSet(SpecialPath.LocalDbFileFullName); ServerMessageSet = new ServerMessageSet(SpecialPath.LocalDbFileFullName); if (VirtualRoot.LocalAppSettingSet.TryGetAppSetting(nameof(KernelOutputKeywordTimestamp), out IAppSetting appSetting) && appSetting.Value is DateTime value) { KernelOutputKeywordTimestamp = value; } else { KernelOutputKeywordTimestamp = Timestamp.UnixBaseTime; } } catch (Exception e) { NTMinerConsole.UserError(e.Message); NTMinerConsole.UserError(e.StackTrace); NTMinerConsole.UserInfo("按任意键退出"); Console.ReadKey(); return; } VirtualRoot.StartTimer(); NTMinerRegistry.SetAutoBoot("NTMinerServices", true); Type thisType = typeof(AppRoot); Run(); } } catch (Exception e) { Logger.ErrorDebugLine(e); } }
static void Main() { VirtualRoot.SetOut(new ConsoleOut()); NTMinerConsole.MainUiOk(); NTMinerConsole.DisbleQuickEditMode(); DevMode.SetDevMode(); Windows.ConsoleHandler.Register(Exit); string thisServerAddress = ServerRoot.HostConfig.ThisServerAddress; Console.Title = $"{nameof(ServerAppType.WsServer)}_{thisServerAddress}"; // 用本节点的地址作为队列名,消费消息时根据路由键区分消息类型 string queue = $"{nameof(ServerAppType.WsServer)}.{thisServerAddress}"; string durableQueue = queue + MqKeyword.DurableQueueEndsWith; AbstractMqMessagePath[] mqMessagePaths = new AbstractMqMessagePath[] { new ReadOnlyUserMqMessagePath(durableQueue), new CalcConfigMqMessagePath(queue), new MinerSignMqMessagePath(queue), new WsServerNodeMqMessagePath(queue), new OperationMqMessagePath(queue), new MinerClientMqMessagePath(queue, thisServerAddress), new ClientTestIdMqMessagePath(queue) }; if (!MqRedis.Create(ServerAppType.WsServer, mqMessagePaths, out IMqRedis mqRedis)) { NTMinerConsole.UserError("启动失败,无法继续,因为服务器上下文创建失败"); return; } IRedis redis = mqRedis; IMq mq = mqRedis; MinerClientMqSender = new MinerClientMqSender(mq); SpeedDataRedis = new SpeedDataRedis(redis); WsServerNodeRedis = new WsServerNodeRedis(redis); OperationMqSender = new OperationMqSender(mq); UserMqSender = new UserMqSender(mq); _wsServerNodeMqSender = new WsServerNodeMqSender(mq); WsServerNodeAddressSet = new WsServerNodeAddressSet(WsServerNodeRedis, _wsServerNodeMqSender); var minerRedis = new MinerDataRedis(redis); var userRedis = new ReadOnlyUserDataRedis(redis); var calcConfigRedis = new CalcConfigDataRedis(redis); VirtualRoot.StartTimer(); // 构造函数中异步访问redis初始化用户列表,因为是异步的所以提前构造 UserSet = new ReadOnlyUserSet(userRedis); MinerSignSet = new MinerSignSet(minerRedis); _wsServer = new SharpWsServerAdapter(ServerRoot.HostConfig); CalcConfigSet = new ReadOnlyCalcConfigSet(calcConfigRedis); MinerClientSessionSet = new MinerClientSessionSet(_wsServer.MinerClientWsSessions); MinerStudioSessionSet = new MinerStudioSessionSet(_wsServer.MinerStudioWsSessions); _started = _wsServer.Start(); if (!_started) { NTMinerConsole.UserError("启动失败,无法继续,因为_wsServer启动失败"); return; } VirtualRoot.RaiseEvent(new WebSocketServerStatedEvent()); Console.ReadKey(true); Exit(); }