Flutter Consul服务集成插件dart_consul的使用

Flutter Consul服务集成插件dart_consul的使用

什么是dart_consul?

dart_consul 是一个用于在终端或命令行界面中创建桌面窗口系统的简单、有限、初级且奇怪的项目。目前仅在我的一台Linux机器上测试过,可能不会在Windows或macOS上正常工作。如果您愿意,可以进行测试并反馈结果。

该项目使用Dart语言编写,因为我在学习Dart以进入Flutter(和Flutter Flame)领域。也许吧,我们拭目以待。

示例截图

以下是 example.dart 运行时的截图:

Screenshot

依赖项

除了一些显而易见的Dart依赖项外,此项目还使用了以下依赖项:

  • termlib 用于终端交互
  • console 用于通过Braille Unicode字符块绘制画布
  • dart_console 通过一些本地代码提供原始终端访问
  • rxdart 用于实现“throttleTime”,这样我就不用自己实现了
  • ansi 用于ANSI样式

没有这些依赖项,这个有趣的小项目将无法存在!

它能工作吗?

嗯,在我的机器上它能工作…… 😂

您可以尝试包含的 example.dart 并自行查看。

基本想法如下:

final desktop = Desktop(...);
desktop.onKey('k', () => doSomething());

final window = Window(
  "some-id",
  "Some Title",
  size: WindowSize.defaultMinMax(Size(60, 40)),
  position: RelativePosition.fromTopLeft(xOffset: 4, yOffset: 2),
  redraw: () => "Hello, world!",
);
desktop.openWindow(window);

它支持基于“Braille”字符的“画布”。这使得您可以像在 example.dart 中一样做些事情。

注意,这种画布功能来自 console

示例动画GIF:

Screenshot

这里有一个快速拼凑的游戏框架更新:

Screenshot

待办事项

对于“版本1”的必备功能:

  • 基本对话系统
  • 基本弹出系统

其他考虑事项:

  • 可能的任务栏显示所有窗口(包括最小化)
  • 可能的任务栏溢出显示剩余窗口
  • 可能的活动窗口标题闪烁(或以其他方式指示,特别是小窗口)
  • 可能的菜单栏系统
  • 可能的改进终端调整大小处理
  • 可能的使用包含依赖项的表格/边框功能
  • 可能使滚动视图、边框视图等成为透明使用的第一个类概念

已完成

  • 绘制窗口
  • 窗口标题栏及控制
  • 控制台输入处理(目前仅限按键)
  • 切换标签
  • 控制台鼠标输入处理
  • 通过按键最小化/最大化/关闭窗口
  • 嵌套按键处理
  • 通过按键移动窗口
  • 通过按键调整窗口大小
  • 窗口钩子(状态和大小)
  • 基本鼠标操作(提升、最小化、最大化、关闭)
  • 通过鼠标调整窗口大小
  • 通过鼠标移动窗口
  • 添加帮助按钮以显示按键配置
  • 添加基本(仅垂直)滚动内容

Bug

  • 重大 快速移动窗口,然后移动另一个窗口会导致第一个窗口再次移动。
  • 重大 聚焦时未正确跳过最小化的窗口。

已修复的Bug

  • 关键 调整大小控件的一个偏移错误。似乎只适用于某些 Position 类型?
  • 重大 标题栏控件不尊重窗口标志。
  • 移动覆盖在窗口太小时显示。
  • 在替换区域中绘制缓冲区到缓冲区会破坏ANSI。 潜在修复:收集被替换的ANSI序列,并添加到 Cell.after 的最后一个单元格。 相关:Cell.reset 应该在 Cell.after 之前发生?现在看起来更有意义。
  • 与前一个相关的:ANSI序列泄漏到绘制的部分。
  • 当窗口向左移动时破坏ANSI。 潜在修复:收集所有剪切掉的ANSI序列并组合成一个。 放置在第一个可见单元格中。

示例代码

以下是 example.dart 的完整示例代码:

import 'dart:async';
import 'dart:io';

import 'package:dart_consul/dart_consul.dart';
import 'package:dart_minilog/dart_minilog.dart';

import 'src/demo_keys.dart';
import 'src/gol.dart';
import 'src/starfield.dart';

void main(List<String> args) async {
  final conIO = TermLibConIO();
  try {
    await createDesktop(conIO);
  } finally {
    conIO.close();
  }
  exit(0); // 强制退出带有运行定时器等
}

Future createDesktop(ConIO conIO) async {
  final desktop = Desktop(conIO: conIO);

  notify(it) => desktop.sendMessage(it);

  // 使用间接方式使菜单条目更易读。但你也可以直接在条目中使用lambda。
  // 你不必使用notify/subscribe。这只是可用的一种简单的内置机制。

  confirmQuit() => notify("quit");
  // showGameOfLife() => notify("show-gol");
  // showStarfield() => notify("show-starfield");
  // changeFps() => notify("change-fps");

  // 注意使用"quit"作为消息来结束[Desktop.run]。
  desktop.subscribe("quit", (_) => desktop.exit()); // TODO确认对话框
  desktop.subscribe("show-gol", (_) => gameOfLife(desktop));
  desktop.subscribe("show-starfield", (_) => starfield(desktop));
  desktop.subscribe("change-fps", (_) => print("TODO"));

  // desktop.interceptSigInt = true;
  desktop.setDefaultKeys();
  desktop.onKey("q", description: "Quit", action: confirmQuit);

  gameOfLife(desktop);
  starfield(desktop);
  addDemoKeys(desktop);
  addAnsiDemo(desktop);

  final log = DebugLog(redraw: () => desktop.redraw());
  addDebugLog(
    desktop,
    log: log,
    key: "<C-w>l",
    position: RelativePosition.fromBottom(yOffset: -1),
  );

  addAutoHelp(
    desktop,
    key: "<C->>",
    position: RelativePosition.fromBottomRight(),
  );

  // 将日志输出重定向到我们的[DebugLog]:
  sink = (e) => log.add(e);
  logLevel = LogLevel.verbose;

  logVerbose("verbose");
  logDebug("debug");
  logInfo("info");
  logWarn("warn");
  logError("error");

  desktop.focusById('stars');

  return await desktop.run();
}

void addAnsiDemo(Desktop desktop) {
  final window = Window("ansi-demo", "ANSI Demo",
      size: WindowSize.fixed(Size(20, 10)),
      position: RelativePosition.autoCentered(),
      redraw: () =>
          "some red\n".red() +
          "some blue\n".bgBlue() +
          "some invers\n".inverse() +
          "some bold\n".bold() +
          "some italic\n".italic() +
          "some underline\n".underline() +
          "some dim\n".dim() +
          "some strike-through\n".strikeThrough());

  window.onKey(
    "q",
    description: "Close window",
    action: () => desktop.closeWindow(window),
  );

  desktop.openWindow(window);
}

更多关于Flutter Consul服务集成插件dart_consul的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Consul服务集成插件dart_consul的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中集成并使用dart_consul插件来与Consul服务进行交互的示例代码。这个示例将展示如何连接到Consul服务器、注册服务和查询服务。

首先,确保你已经在pubspec.yaml文件中添加了dart_consul依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_consul: ^x.y.z  # 替换为最新版本号

然后运行flutter pub get来获取依赖。

接下来,在你的Flutter项目中,你可以使用以下代码来与Consul进行交互:

import 'package:flutter/material.dart';
import 'package:dart_consul/dart_consul.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Consul Integration'),
        ),
        body: ConsulIntegrationExample(),
      ),
    );
  }
}

class ConsulIntegrationExample extends StatefulWidget {
  @override
  _ConsulIntegrationExampleState createState() => _ConsulIntegrationExampleState();
}

class _ConsulIntegrationExampleState extends State<ConsulIntegrationExample> {
  String result = '';

  @override
  void initState() {
    super.initState();
    _connectToConsul();
  }

  Future<void> _connectToConsul() async {
    try {
      // 配置Consul客户端
      var consulClient = ConsulClient(
        scheme: 'http',  // 或者 'https'
        host: 'localhost',
        port: 8500,
      );

      // 注册服务
      var registration = ServiceRegistration(
        id: 'my-flutter-app',
        name: 'my-flutter-service',
        address: '127.0.0.1',
        port: 8080,
        tags: ['web'],
        check: HttpCheck(
          path: '/health',
          interval: '10s',
        ),
      );

      await consulClient.agent.service.register(registration);
      print('Service registered successfully');

      // 查询服务
      var services = await consulClient.health.service(service: 'my-flutter-service');
      setState(() {
        result = services.map((service) => service.service.name).join(', ');
      });
    } catch (e) {
      print('Error: $e');
      setState(() {
        result = 'Error: $e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text('Consul Integration Result:'),
          Text(result),
        ],
      ),
    );
  }
}

注意事项

  1. Consul Server: 确保你的Consul服务器正在运行,并且可以通过你提供的hostport访问。
  2. 服务地址和端口: 在ServiceRegistration中,确保addressport是运行Flutter应用的服务器的实际地址和端口。
  3. 健康检查路径: 在HttpCheck中,path应该是一个有效的健康检查路径,该路径应该在你的Flutter应用中实现并返回HTTP 200状态码。

运行

将上述代码添加到你的Flutter项目中,并运行应用。你应该会看到应用与Consul服务器进行交互的结果,包括服务注册和查询服务的输出。

这个示例代码展示了如何使用dart_consul插件进行基本的Consul集成。根据你的具体需求,你可能需要调整代码以处理更多的Consul功能。

回到顶部