- Moved database to subdir specified by env - Default data dir /data - Move loggers to cronJob onTick - Added volume for data dir in Docker compose - Create any missing dir specified by env
This commit is contained in:
parent
aaa85e99cb
commit
9850017e3a
@ -14,4 +14,5 @@ BANK_OAUTH_REDIRECT_URI=http://your-redirect-uri.com
|
||||
BANK_ACCOUNT_IDS=your-account-id1,your-account-id2
|
||||
# Configuration
|
||||
LOG_LEVEL=info# trace | error | warn | info | debug | trace
|
||||
DB_DIRECTORY=data# Relative path, must not start or end with /
|
||||
DB_FILENAME=default
|
||||
|
@ -2,7 +2,7 @@ name: Deploy application
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
@ -25,6 +25,7 @@ jobs:
|
||||
BANK_ACCOUNT_IDS: ${{ secrets.BANK_ACCOUNT_IDS }}
|
||||
# Configuration
|
||||
LOG_LEVEL: ${{ var.LOG_LEVEL }}
|
||||
DB_DIRECTORY: ${{ var.DB_DIRECTORY }}
|
||||
DB_FILENAME: ${{ var.DB_FILENAME }}
|
||||
|
||||
steps:
|
||||
|
@ -19,6 +19,7 @@ export const BANK_OAUTH_CLIENT_SECRET = getOrThrow("BANK_OAUTH_CLIENT_SECRET")
|
||||
export const BANK_ACCOUNT_IDS = getArrayOrThrow("BANK_ACCOUNT_IDS")
|
||||
|
||||
// Configuration
|
||||
export const DB_DIRECTORY = getOrDefault("DB_DIRECTORY", "data")
|
||||
export const DB_FILENAME = getOrDefault("DB_FILENAME", "default")
|
||||
export const LOG_LEVEL = getOrDefault("LOG_LEVEL", "info")
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
services:
|
||||
# TODO Database in storage
|
||||
server:
|
||||
container_name: actual_budget_sparebank1
|
||||
restart: no # TODO unless-stopped
|
||||
container_name: actual_sparebank1_cronjob
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: .
|
||||
environment:
|
||||
@ -19,4 +18,10 @@ services:
|
||||
- BANK_OAUTH_REDIRECT_URI
|
||||
- BANK_ACCOUNT_IDS
|
||||
- LOG_LEVEL
|
||||
- DB_DIRECTORY # Required for Docker Compose
|
||||
- DB_FILENAME
|
||||
volumes:
|
||||
- data:/${DB_DIRECTORY}
|
||||
|
||||
volumes:
|
||||
data:
|
||||
|
@ -17,8 +17,8 @@ export type TokenResponseRaw = {
|
||||
|
||||
export type TokenKey = "access-token" | "refresh-token"
|
||||
|
||||
export function createDb(filename: string) {
|
||||
const db = new Database(filename)
|
||||
export function createDb(filepath: string) {
|
||||
const db = new Database(filepath)
|
||||
db.pragma("journal_mode = WAL")
|
||||
db.exec(
|
||||
"CREATE TABLE IF NOT EXISTS tokens ('key' VARCHAR PRIMARY KEY, token VARCHAR NOT NULL, expires_at DATETIME NOT NULL)",
|
||||
|
@ -93,6 +93,7 @@ export class Sparebank1Impl implements Sparebank1 {
|
||||
async transactionsPastDay(
|
||||
...accountKeys: ReadonlyArray<string>
|
||||
): Promise<TransactionResponse> {
|
||||
// TODO API is inclusive, today should equal lastDay
|
||||
const today = dayjs()
|
||||
const lastDay = today.subtract(1, "day")
|
||||
return await Api.transactions(await this.getAccessToken(), accountKeys, {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { CronJob } from "cron"
|
||||
import logger from "@/logger.ts"
|
||||
|
||||
/**
|
||||
* Run a function every day at 1 AM, Oslo time.
|
||||
@ -8,7 +9,11 @@ import { CronJob } from "cron"
|
||||
export function cronJobDaily(onTick: () => Promise<void>): CronJob {
|
||||
return CronJob.from({
|
||||
cronTime: "0 0 1 * * *",
|
||||
onTick,
|
||||
onTick: async () => {
|
||||
logger.info("Starting daily job")
|
||||
await onTick()
|
||||
logger.info("Finished daily job")
|
||||
},
|
||||
start: true,
|
||||
timeZone: "Europe/Oslo",
|
||||
})
|
||||
|
29
src/main.ts
29
src/main.ts
@ -10,6 +10,7 @@ import {
|
||||
ACTUAL_ACCOUNT_IDS,
|
||||
ACTUAL_DATA_DIR,
|
||||
BANK_ACCOUNT_IDS,
|
||||
DB_DIRECTORY,
|
||||
DB_FILENAME,
|
||||
} from "../config.ts"
|
||||
import logger from "@/logger.ts"
|
||||
@ -19,10 +20,9 @@ import * as fs from "node:fs"
|
||||
import { CronJob } from "cron"
|
||||
|
||||
// TODO Transports api for pino https://github.com/pinojs/pino/blob/HEAD/docs/transports.md
|
||||
// TODO create Dockerfile and docker-compose.yml
|
||||
// TODO Gitea workflow
|
||||
// TODO move tsx to devDependency. Requires ts support for Node with support for @ alias
|
||||
// TODO global exception handler, log and graceful shutdown
|
||||
// TODO verbatimSyntax in tsconfig, conflicts with jest
|
||||
|
||||
export async function daily(actual: Actual, bank: Bank): Promise<void> {
|
||||
// Fetch transactions from the bank
|
||||
@ -60,22 +60,23 @@ async function fetchTransactionsFromPastDay(
|
||||
return response.transactions
|
||||
}
|
||||
|
||||
function createCacheDirIfMissing(): void {
|
||||
if (!fs.existsSync(ACTUAL_DATA_DIR)) {
|
||||
logger.info(`Missing '${ACTUAL_DATA_DIR}', creating...`)
|
||||
fs.mkdirSync(ACTUAL_DATA_DIR)
|
||||
function createDirIfMissing(directory: string): void {
|
||||
if (!fs.existsSync(directory)) {
|
||||
logger.info(`Missing '${directory}', creating...`)
|
||||
fs.mkdirSync(directory, { recursive: true })
|
||||
}
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
logger.info("Starting application")
|
||||
|
||||
createCacheDirIfMissing()
|
||||
createDirIfMissing(ACTUAL_DATA_DIR)
|
||||
createDirIfMissing(DB_DIRECTORY)
|
||||
|
||||
const actual = await ActualImpl.init()
|
||||
const databaseFileName = `${DB_FILENAME}.sqlite`
|
||||
const db = createDb(databaseFileName)
|
||||
logger.info(`Started SQLlite database with filename="${databaseFileName}"`)
|
||||
const databaseFilePath = `${DB_DIRECTORY}/${DB_FILENAME}.sqlite`
|
||||
const db = createDb(databaseFilePath)
|
||||
logger.info(`Started Sqlite database at '${databaseFilePath}'`)
|
||||
const bank = new Sparebank1Impl(db)
|
||||
|
||||
process.on("SIGINT", async () => {
|
||||
@ -91,14 +92,10 @@ async function main(): Promise<void> {
|
||||
}
|
||||
|
||||
logger.info("Waiting for CRON job to start")
|
||||
cronJob = cronJobDaily(async () => {
|
||||
logger.info("Running daily job")
|
||||
await daily(actual, bank)
|
||||
logger.info("Finished daily job")
|
||||
})
|
||||
cronJob = cronJobDaily(async () => await daily(actual, bank))
|
||||
|
||||
async function shutdown(): Promise<void> {
|
||||
logger.info("Shutting down")
|
||||
logger.info("Shutting down, Bye!")
|
||||
await actual.shutdown()
|
||||
db.close()
|
||||
cronJob?.stop()
|
||||
|
Loading…
x
Reference in New Issue
Block a user