Fosi Fossil Service
Small teams. Open source. Built on Fossil.

IaC / SwiftFlow

High-performance WMS with wave picking, smart routing, and real-time inventory visibility.

Public | Owner: IaC | Default branch: trunk | Last update: 2026-10-23 14:37

Artifact 639b58612e0a25ba8b009229cba283950afe5c7c81833fa1d5fba068c0187a6f:


import access
import app.{type Context, Context}
import config
import database
import gleam/erlang/process
import gleam/int
import logging
import mist
import poller
import router
import schema
import session
import sync_lock
import wisp
import wisp/wisp_mist

pub fn main() {
  logging.configure()
  wisp.configure_logger()
  config.load_dotenv()
  case config.load() {
    Error(message) -> halt(message)
    Ok(cfg) -> boot(cfg)
  }
}

fn boot(cfg: config.Config) -> Nil {
  case database.start(cfg) {
    Error(database.DbError(message)) -> halt(message)
    Ok(db) ->
      case schema.migrate(db) {
        Error(database.DbError(message)) -> halt(message)
        Ok(_) ->
          case session.start(
            cfg.ql361_username,
            cfg.ql361_password,
            cfg.ql361_base_url,
            cfg.request_gap_ms,
          ),
            sync_lock.start()
          {
            Error(_), _ -> halt("QL361 会话进程启动失败")
            _, Error(_) -> halt("同步锁进程启动失败")
            Ok(ql_session), Ok(lock) -> {
              let auth_cfg = config.load_auth()
              bootstrap_admin(db, auth_cfg)
              let ctx =
                Context(
                  config: cfg,
                  auth: auth_cfg,
                  db: db,
                  session: ql_session,
                  lock: lock,
                )
              let _ = poller.start(ctx)
              logging.log(
                logging.Info,
                "SwiftFlow 已启动,数据库 "
                  <> driver_name(cfg)
                  <> ",订单轮询 "
                  <> int.to_string(cfg.order_poll_ms / 1000)
                  <> " 秒,请求间隔 "
                  <> int.to_string(cfg.request_gap_ms)
                  <> " 毫秒",
              )
              serve(ctx)
            }
          }
      }
  }
}

fn serve(ctx: Context) -> Nil {
  let secret_key_base = wisp.random_string(64)
  let handler = fn(req) { router.handle_request(req, ctx) }
  let assert Ok(_) =
    wisp_mist.handler(handler, secret_key_base)
    |> mist.new
    |> mist.port(ctx.config.http_port)
    |> mist.start

  process.sleep_forever()
}

fn bootstrap_admin(db: database.Database, auth_cfg: config.AuthConfig) -> Nil {
  case access.bootstrap_admin(db, auth_cfg) {
    Error(message) -> halt(message)
    Ok(access.AdminCreated(username)) ->
      logging.log(logging.Info, "已创建首个超级管理员 " <> username)
    Ok(access.UsersExist) -> Nil
    Ok(access.AdminNotConfigured) ->
      logging.log(
        logging.Warning,
        "还没有任何用户,且未配置 SWIFTFLOW_ADMIN_USERNAME / SWIFTFLOW_ADMIN_PASSWORD,暂时无人能登录",
      )
  }
}

fn driver_name(cfg: config.Config) -> String {
  case cfg.db_driver {
    config.Sqlite -> "sqlite"
    config.Postgres -> "postgres"
  }
}

fn halt(message: String) -> Nil {
  logging.log(logging.Error, message)
  panic
}

Clone

You can clone this repository with the following command:

fossil clone https://fosi.dev/IaC/SwiftFlow

Contribute

The best way to contribute is through e-mail. See the project documentation for more details.