اجرای یک برنامه فینچ

یک برنامه فینچ به دو فایل نیاز دارد: app.dart (تنظیمات برنامه) و یک نقطه ورود — معمولاً bin/main.dart برای production یا lib/serve.dart برای توسعه با نظارت بر فایل.

app.dart — تنظیمات برنامه

app.dart نمونه FinchApp را می‌سازد، مسیرها را ثبت می‌کند، و main() را تعریف می‌کند. این ساختار استاندارد بر اساس پروژه مثال فینچ است:

// lib/app.dart
import 'package:finch/finch_app.dart';
import 'package:finch/finch_tools.dart';
import 'package:finch/finch_route.dart';
import 'package:finch/finch_console.dart';
import 'route/web_route.dart';

FinchConfigs configs = FinchConfigs(
  port: env.getInt('DOMAIN_PORT', 8080),
  domain: env.get('DOMAIN', 'localhost'),
  publicDir: pathTo(env.get('PUBLIC_DIR', './public')),
  widgetsPath: pathTo(env.get('WIDGETS_PATH', './lib/widgets')),
  widgetsType: env.get('WIDGETS_TYPE', 'j2.html'),
  languagePath: pathTo(env.get('LANGUAGE_PATH', './lib/languages')),
  enableLocalDebugger: env.getBool('ENABLE_LOCAL_DEBUGGER', false),
);

final app = FinchApp(configs: configs);

void main([List<String>? args]) async {
  app.addRouting(getWebRoute);

  app.start(args).then((value) {
    Console.p('Server started: http://localhost:${value.port}');
  });
}

تابع مسیر

مسیرها در تابعی تعریف می‌شوند که یک Request دریافت کرده و Future<List<FinchRoute>> برمی‌گرداند:

// lib/route/web_route.dart
import 'package:finch/finch_route.dart';
import '../controllers/home_controller.dart';

final homeController = HomeController();

Future<List<FinchRoute>> getWebRoute() async {
  return [
    FinchRoute(
      key: 'root',
      path: '/',
      methods: Methods.ONLY_GET,
      index: homeController.index,
    ),
    FinchRoute(
      key: 'root.api',
      path: 'api/hello',
      methods: Methods.ONLY_GET,
      index: homeController.hello,
    ),
  ];
}

مسیرهای Inline (میان‌بر)

برای مسیرهای ساده یا سریع، FinchApp متدهای میان‌بر دارد. callback ی که index دریافت می‌کند Request را به عنوان پارامتر می‌گیرد:

app
  ..get(
    path: '/ping',
    index: (rq) async => rq.renderString(text: 'pong'),
  )
  ..post(
    path: '/echo',
    index: (rq) async {
      var body = rq.get<String>('message', def: '');
      return rq.renderString(text: body);
    },
  )
  ..postGet(
    path: '/form',
    index: (rq) async => rq.renderString(text: 'GET or POST'),
  );

توسعه: serve.dart با نظارت بر فایل

در طول توسعه، از lib/serve.dart (تولیدشده توسط finch create) استفاده کنید. این فایل main() از app.dart را اجرا کرده و فایل‌های widget و زبان را برای تغییرات رصد می‌کند و بدون راه‌اندازی مجدد کامل سرور، source map های دارت را به‌صورت خودکار مجدداً تولید می‌کند:

finch serve -p lib/serve.dart
# یا
dart run lib/serve.dart

این watcher با هر تغییر فایل، مبدل‌های LanguageToDart و WidgetToDart را فراخوانی می‌کند و سپس به نوار debugger متصل‌شده اطلاع می‌دهد تا صفحه را بارگذاری مجدد کند.

Production: کامپایل به باینری

برای کامپایل به یک باینری native مستقل:

finch build -a lib/app.dart -o ./build/app
./build/app

یا از Dockerfile / docker-compose ارائه‌شده استفاده کنید. به Docker مراجعه کنید.

Cron Jobs

وظایف زمان‌بندی‌شده را با app.registerCron() ثبت کنید:

app.registerCron(
  FinchCron(
    schedule: FinchCron.evryDay(2),   // هر ۲ روز
    onCron: (index, cron) async {
      // اجرای وظیفه پاک‌سازی
    },
    delayFirstMoment: true,
  ).start(),
);

// عبارت cron استاندارد
app.registerCron(
  FinchCron(
    schedule: '0 * * * *',  // هر ساعت
    onCron: (index, cron) async {
      // اجرای وظیفه ساعتی
    },
  ).start(),
);

مدیریت خطاهای ثبت‌شده

با ثبت یک callback در app.onError() می‌توانید هر بار که خطایی از طریق Console ثبت می‌شود (مثلاً Console.e(...)) مطلع شوید، برای مثال برای ارسال آن به یک سرویس مانیتورینگ خارجی:

app.onError((error, type) {
  // 'type' سطح لاگ است، مثلاً 'error'
  MyMonitoringService.report(error, type);
});

ارسال آرگومان‌ها

همیشه args از main را به app.start() منتقل کنید. این امکان دستوراتی مانند migrate و دستورات سفارشی را فراهم می‌کند:

void main([List<String>? args]) async {
  app.addRouting(getWebRoute);
  app.start(args);
}
dart run lib/app.dart migrate --init