@@ -10,67 +10,132 @@ import { UserService } from "./services/user";
1010import { WalletService } from "./services/wallet" ;
1111import { DispatchJob } from "./jobs/dispatch" ;
1212import { MessageService } from "./services/message" ;
13- import { getEnv } from "./env" ;
13+ import { Env , getEnv } from "./env" ;
1414import { SampleJob } from "./jobs/sample" ;
1515import { CleanupJob } from "./jobs/cleanup" ;
1616
17- const env = getEnv ( ) ;
18- const prisma = new PrismaClient ( { datasourceUrl : env . DATABASE_URL } ) ;
1917const logger = pino ( ) ;
20- const bot = new Bot < Context & SessionFlavor < unknown > > ( env . BOT_TOKEN ) ;
2118
22- /* Services */
19+ /**
20+ * Main function to instantiate and run all components of the application
21+ */
22+ async function main ( ) {
23+ const env = getEnv ( ) ;
24+ const prisma = await getPrismaClient ( env ) ;
25+ const services = getServices ( prisma , env ) ;
26+ const bot = getBot ( env , services ) ;
27+ const jobs = getJobs ( env , services , bot ) ;
2328
24- const user = new UserService ( prisma ) ;
25- const wallet = new WalletService ( prisma ) ;
26- const message = new MessageService ( prisma , env . MAX_ATTEMPTS ) ;
29+ run ( bot ) ;
2730
28- /* Handlers */
31+ jobs . forEach ( ( job ) => job . start ( ) ) ;
32+ }
2933
30- const start = getStartHandler ( logger . child ( { handler : "start" } ) , message , user , wallet ) ;
31- const add = getAddHandler ( logger . child ( { handler : "add" } ) , message , user , wallet ) ;
32- const list = getListHandler ( logger . child ( { handler : "list" } ) , message , user ) ;
33- const remove = getRemoveHandler ( logger . child ( { handler : "remove" } ) , message , user ) ;
34+ /**
35+ * Instantiate and configure the Prisma Client for database interactions
36+ */
37+ async function getPrismaClient ( env : Env ) : Promise < PrismaClient > {
38+ const prisma = new PrismaClient ( { datasourceUrl : env . DATABASE_URL } ) ;
3439
35- /* Telegram Bot */
40+ // SQlite Database optimizations.
41+ // Remove or change for other databases
42+ await prisma . $queryRawUnsafe ( `PRAGMA journal_mode=WAL;` ) ;
43+ await prisma . $queryRawUnsafe ( `PRAGMA synchronous=NORMAL;` ) ;
3644
37- const getSessionKey = ( ctx : Context ) => ctx . chat ?. id . toString ( ) ;
38- bot . use ( sequentialize ( getSessionKey ) ) ;
39- bot . use ( session ( { getSessionKey } ) ) ;
45+ return prisma ;
46+ }
4047
41- bot . command ( "start" , start ) ;
42- bot . command ( "add" , add ) ;
43- bot . command ( "list" , list ) ;
44- bot . command ( "remove" , remove ) ;
48+ /**
49+ * Instantiate all services used across the application
50+ */
51+ function getServices ( prisma : PrismaClient , env : Env ) {
52+ // Service responsible for managing messages
53+ const message = new MessageService ( prisma , env . MAX_ATTEMPTS ) ;
4554
46- bot . catch ( ( err ) =>
47- logger . error ( { err, userId : err . ctx . from ?. id , message : err . ctx . message ?. text } , "Failure" ) ,
48- ) ;
55+ // Service responsible for managing users
56+ const user = new UserService ( prisma ) ;
4957
50- run ( bot ) ;
58+ // Service responsible for managing wallets
59+ const wallet = new WalletService ( prisma ) ;
5160
52- logger . info ( "Started" ) ;
61+ return {
62+ message,
63+ user,
64+ wallet,
65+ } ;
66+ }
5367
54- /* Jobs */
68+ /**
69+ * Instantiate and configure the Telegram Bot with all commands and middleware
70+ */
71+ function getBot ( env : Env , services : ReturnType < typeof getServices > ) {
72+ const bot = new Bot < Context & SessionFlavor < unknown > > ( env . BOT_TOKEN ) ;
5573
56- new DispatchJob (
57- logger . child ( { job : "dispatch" } ) ,
58- message ,
59- env . DISPATCH_CRON ,
60- bot ,
61- env . MESSAGES_PER_DISPATCH ,
62- ) . start ( ) ;
74+ // Middleware that ensures order of message processing per user
75+ const getSessionKey = ( ctx : Context ) => ctx . chat ?. id . toString ( ) ;
76+ bot . use ( sequentialize ( getSessionKey ) ) ;
77+ bot . use ( session ( { getSessionKey } ) ) ;
6378
64- new CleanupJob (
65- logger . child ( { job : "cleanup" } ) ,
66- message ,
67- env . CLEANUP_CRON ,
68- env . CLEANUP_CUTOFF ,
69- ) . start ( ) ;
79+ const { message, user, wallet } = services ;
7080
71- new SampleJob (
72- logger . child ( { job : "sample" } ) ,
73- message ,
74- "*/10 * * * * *" , // Every 10 seconds
75- wallet ,
76- ) . start ( ) ;
81+ // Command used to onboard a new user and optionally subscribe a wallet
82+ bot . command ( "start" , getStartHandler ( logger . child ( { command : "start" } ) , message , user , wallet ) ) ;
83+
84+ // Command used to subscribe a new wallet
85+ bot . command ( "add" , getAddHandler ( logger . child ( { command : "add" } ) , message , user , wallet ) ) ;
86+
87+ // Command used to list all subscribed wallets
88+ bot . command ( "list" , getListHandler ( logger . child ( { command : "list" } ) , message , user ) ) ;
89+
90+ // Command used to unsubscribe a wallet
91+ bot . command ( "remove" , getRemoveHandler ( logger . child ( { command : "remove" } ) , message , user ) ) ;
92+
93+ // Global error handler for the bot
94+ bot . catch ( ( err ) =>
95+ logger . error ( { err, userId : err . ctx . from ?. id , message : err . ctx . message ?. text } , "Failure" ) ,
96+ ) ;
97+
98+ return bot ;
99+ }
100+
101+ /**
102+ * Instantiate all jobs for scheduled background processing
103+ */
104+ function getJobs (
105+ env : Env ,
106+ services : ReturnType < typeof getServices > ,
107+ bot : ReturnType < typeof getBot > ,
108+ ) {
109+ // Job that dispatches queued messages to users
110+ const dispatchJob = new DispatchJob (
111+ logger . child ( { job : "dispatch" } ) ,
112+ services . message ,
113+ env . DISPATCH_CRON ,
114+ bot ,
115+ env . MESSAGES_PER_DISPATCH ,
116+ ) ;
117+
118+ // Job that deletes old messages from the database
119+ const cleanupJob = new CleanupJob (
120+ logger . child ( { job : "cleanup" } ) ,
121+ services . message ,
122+ env . CLEANUP_CRON ,
123+ env . CLEANUP_CUTOFF ,
124+ ) ;
125+
126+ // Sample job for demo purposes
127+ // Can be removed or modified as needed
128+ const sampleJob = new SampleJob (
129+ logger . child ( { job : "sample" } ) ,
130+ services . message ,
131+ "*/10 * * * * *" , // Every 10 seconds
132+ services . wallet ,
133+ ) ;
134+
135+ return [ dispatchJob , cleanupJob , sampleJob ] ;
136+ }
137+
138+ main ( ) . catch ( ( err ) => {
139+ logger . error ( { err } , "Main function failed" ) ;
140+ process . exit ( 1 ) ;
141+ } ) ;
0 commit comments