factory.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "log/slog"
  6. "net"
  7. "github.com/kelseyhightower/envconfig"
  8. "github.com/mk6i/retro-aim-server/config"
  9. "github.com/mk6i/retro-aim-server/foodgroup"
  10. "github.com/mk6i/retro-aim-server/server/http"
  11. "github.com/mk6i/retro-aim-server/server/oscar"
  12. "github.com/mk6i/retro-aim-server/server/oscar/handler"
  13. "github.com/mk6i/retro-aim-server/server/oscar/middleware"
  14. "github.com/mk6i/retro-aim-server/server/toc"
  15. "github.com/mk6i/retro-aim-server/state"
  16. )
  17. // Container groups together common dependencies.
  18. type Container struct {
  19. cfg config.Config
  20. chatSessionManager *state.InMemoryChatSessionManager
  21. hmacCookieBaker state.HMACCookieBaker
  22. inMemorySessionManager *state.InMemorySessionManager
  23. logger *slog.Logger
  24. sqLiteUserStore *state.SQLiteUserStore
  25. }
  26. // MakeCommonDeps creates common dependencies used by the food group services.
  27. func MakeCommonDeps() (Container, error) {
  28. c := Container{}
  29. err := envconfig.Process("", &c.cfg)
  30. if err != nil {
  31. return c, fmt.Errorf("unable to process app config: %s\n", err.Error())
  32. }
  33. if c.cfg.OSCARHost == "0.0.0.0" {
  34. return c, errors.New("invalid config: OSCAR_HOST cannot be set to " +
  35. "the 'all interfaces' IP (0.0.0.0). it must be a specific IP " +
  36. "address or hostname reachable by AIM/ICQ clients")
  37. }
  38. c.sqLiteUserStore, err = state.NewSQLiteUserStore(c.cfg.DBPath)
  39. if err != nil {
  40. return c, fmt.Errorf("unable to create feedbag store: %s\n", err.Error())
  41. }
  42. c.hmacCookieBaker, err = state.NewHMACCookieBaker()
  43. if err != nil {
  44. return c, fmt.Errorf("unable to create HMAC cookie baker: %s\n", err.Error())
  45. }
  46. c.logger = middleware.NewLogger(c.cfg)
  47. c.inMemorySessionManager = state.NewInMemorySessionManager(c.logger)
  48. c.chatSessionManager = state.NewInMemoryChatSessionManager(c.logger)
  49. return c, nil
  50. }
  51. // Admin creates an OSCAR server for the Admin food group.
  52. func Admin(deps Container) oscar.AdminServer {
  53. logger := deps.logger.With("svc", "ADMIN")
  54. adminService := foodgroup.NewAdminService(
  55. deps.sqLiteUserStore,
  56. deps.sqLiteUserStore,
  57. deps.inMemorySessionManager,
  58. deps.inMemorySessionManager,
  59. deps.logger,
  60. )
  61. authService := foodgroup.NewAuthService(
  62. deps.cfg,
  63. deps.inMemorySessionManager,
  64. deps.chatSessionManager,
  65. deps.sqLiteUserStore,
  66. deps.hmacCookieBaker,
  67. deps.chatSessionManager,
  68. deps.sqLiteUserStore,
  69. deps.inMemorySessionManager,
  70. )
  71. oServiceService := foodgroup.NewOServiceServiceForAdmin(
  72. deps.cfg,
  73. logger,
  74. deps.inMemorySessionManager,
  75. deps.sqLiteUserStore,
  76. deps.inMemorySessionManager,
  77. )
  78. return oscar.AdminServer{
  79. AuthService: authService,
  80. Config: deps.cfg,
  81. Handler: handler.NewAdminRouter(handler.Handlers{
  82. AdminHandler: handler.NewAdminHandler(logger, adminService),
  83. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  84. }),
  85. Logger: logger,
  86. OnlineNotifier: oServiceService,
  87. ListenAddr: net.JoinHostPort("", deps.cfg.AdminPort),
  88. }
  89. }
  90. // Alert creates an OSCAR server for the Alert food group.
  91. func Alert(deps Container) oscar.BOSServer {
  92. logger := deps.logger.With("svc", "ALERT")
  93. sessionManager := state.NewInMemorySessionManager(logger)
  94. authService := foodgroup.NewAuthService(
  95. deps.cfg,
  96. sessionManager,
  97. deps.chatSessionManager,
  98. deps.sqLiteUserStore,
  99. deps.hmacCookieBaker,
  100. deps.chatSessionManager,
  101. deps.sqLiteUserStore,
  102. nil,
  103. )
  104. oServiceService := foodgroup.NewOServiceServiceForAlert(
  105. deps.cfg,
  106. logger,
  107. sessionManager,
  108. deps.sqLiteUserStore,
  109. sessionManager,
  110. )
  111. return oscar.BOSServer{
  112. AuthService: authService,
  113. Config: deps.cfg,
  114. Handler: handler.NewAlertRouter(handler.Handlers{
  115. AlertHandler: handler.NewAlertHandler(logger),
  116. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  117. }),
  118. Logger: logger,
  119. OnlineNotifier: oServiceService,
  120. ListenAddr: net.JoinHostPort("", deps.cfg.AlertPort),
  121. }
  122. }
  123. // Auth creates an OSCAR server for the Auth food group.
  124. func Auth(deps Container) oscar.AuthServer {
  125. logger := deps.logger.With("svc", "AUTH")
  126. authHandler := foodgroup.NewAuthService(
  127. deps.cfg,
  128. deps.inMemorySessionManager,
  129. deps.chatSessionManager,
  130. deps.sqLiteUserStore,
  131. deps.hmacCookieBaker,
  132. deps.chatSessionManager,
  133. deps.sqLiteUserStore,
  134. nil,
  135. )
  136. return oscar.AuthServer{
  137. AuthService: authHandler,
  138. Config: deps.cfg,
  139. Logger: logger,
  140. }
  141. }
  142. // BART creates an OSCAR server for the BART food group.
  143. func BART(deps Container) oscar.BOSServer {
  144. logger := deps.logger.With("svc", "BART")
  145. sessionManager := state.NewInMemorySessionManager(logger)
  146. bartService := foodgroup.NewBARTService(
  147. logger,
  148. deps.sqLiteUserStore,
  149. sessionManager,
  150. deps.sqLiteUserStore,
  151. sessionManager,
  152. )
  153. authService := foodgroup.NewAuthService(
  154. deps.cfg,
  155. sessionManager,
  156. deps.chatSessionManager,
  157. deps.sqLiteUserStore,
  158. deps.hmacCookieBaker,
  159. deps.chatSessionManager,
  160. deps.sqLiteUserStore,
  161. nil,
  162. )
  163. oServiceService := foodgroup.NewOServiceServiceForBART(
  164. deps.cfg,
  165. logger,
  166. sessionManager,
  167. deps.sqLiteUserStore,
  168. sessionManager,
  169. )
  170. return oscar.BOSServer{
  171. AuthService: authService,
  172. Config: deps.cfg,
  173. Handler: handler.NewBARTRouter(handler.Handlers{
  174. BARTHandler: handler.NewBARTHandler(logger, bartService),
  175. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  176. }),
  177. ListenAddr: net.JoinHostPort("", deps.cfg.BARTPort),
  178. Logger: logger,
  179. OnlineNotifier: oServiceService,
  180. }
  181. }
  182. // BOS creates an OSCAR server for the BOS food group.
  183. func BOS(deps Container) oscar.BOSServer {
  184. logger := deps.logger.With("svc", "BOS")
  185. authService := foodgroup.NewAuthService(
  186. deps.cfg,
  187. deps.inMemorySessionManager,
  188. deps.chatSessionManager,
  189. deps.sqLiteUserStore,
  190. deps.hmacCookieBaker,
  191. deps.chatSessionManager,
  192. deps.sqLiteUserStore,
  193. nil,
  194. )
  195. bartService := foodgroup.NewBARTService(
  196. logger,
  197. deps.sqLiteUserStore,
  198. deps.inMemorySessionManager,
  199. deps.sqLiteUserStore,
  200. deps.inMemorySessionManager,
  201. )
  202. buddyService := foodgroup.NewBuddyService(
  203. deps.inMemorySessionManager,
  204. deps.sqLiteUserStore,
  205. deps.sqLiteUserStore,
  206. deps.inMemorySessionManager,
  207. )
  208. chatNavService := foodgroup.NewChatNavService(logger, deps.sqLiteUserStore)
  209. feedbagService := foodgroup.NewFeedbagService(
  210. logger,
  211. deps.inMemorySessionManager,
  212. deps.sqLiteUserStore,
  213. deps.sqLiteUserStore,
  214. deps.sqLiteUserStore,
  215. deps.inMemorySessionManager,
  216. )
  217. permitDenyService := foodgroup.NewPermitDenyService(
  218. deps.sqLiteUserStore,
  219. deps.sqLiteUserStore,
  220. deps.inMemorySessionManager,
  221. deps.inMemorySessionManager,
  222. )
  223. icbmService := foodgroup.NewICBMService(
  224. deps.inMemorySessionManager,
  225. deps.sqLiteUserStore,
  226. deps.sqLiteUserStore,
  227. deps.inMemorySessionManager,
  228. )
  229. icqService := foodgroup.NewICQService(deps.inMemorySessionManager, deps.sqLiteUserStore, deps.sqLiteUserStore,
  230. logger, deps.inMemorySessionManager, deps.sqLiteUserStore)
  231. locateService := foodgroup.NewLocateService(
  232. deps.inMemorySessionManager,
  233. deps.sqLiteUserStore,
  234. deps.sqLiteUserStore,
  235. deps.inMemorySessionManager,
  236. )
  237. oServiceService := foodgroup.NewOServiceServiceForBOS(
  238. deps.cfg,
  239. deps.inMemorySessionManager,
  240. logger,
  241. deps.hmacCookieBaker,
  242. deps.sqLiteUserStore,
  243. deps.sqLiteUserStore,
  244. deps.inMemorySessionManager,
  245. )
  246. userLookupService := foodgroup.NewUserLookupService(deps.sqLiteUserStore)
  247. return oscar.BOSServer{
  248. AuthService: authService,
  249. BuddyListRegistry: deps.sqLiteUserStore,
  250. Config: deps.cfg,
  251. DepartureNotifier: buddyService,
  252. ChatSessionManager: deps.chatSessionManager,
  253. Handler: handler.NewBOSRouter(handler.Handlers{
  254. AlertHandler: handler.NewAlertHandler(logger),
  255. BARTHandler: handler.NewBARTHandler(logger, bartService),
  256. BuddyHandler: handler.NewBuddyHandler(logger, buddyService),
  257. ChatNavHandler: handler.NewChatNavHandler(chatNavService, logger),
  258. FeedbagHandler: handler.NewFeedbagHandler(logger, feedbagService),
  259. ICQHandler: handler.NewICQHandler(logger, icqService),
  260. ICBMHandler: handler.NewICBMHandler(logger, icbmService),
  261. LocateHandler: handler.NewLocateHandler(locateService, logger),
  262. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  263. PermitDenyHandler: handler.NewPermitDenyHandler(logger, permitDenyService),
  264. UserLookupHandler: handler.NewUserLookupHandler(logger, userLookupService),
  265. }),
  266. Logger: logger,
  267. OnlineNotifier: oServiceService,
  268. ListenAddr: net.JoinHostPort("", deps.cfg.BOSPort),
  269. }
  270. }
  271. // Chat creates an OSCAR server for the Chat food group.
  272. func Chat(deps Container) oscar.ChatServer {
  273. logger := deps.logger.With("svc", "CHAT")
  274. sessionManager := state.NewInMemorySessionManager(logger)
  275. authService := foodgroup.NewAuthService(
  276. deps.cfg,
  277. sessionManager,
  278. deps.chatSessionManager,
  279. deps.sqLiteUserStore,
  280. deps.hmacCookieBaker,
  281. deps.chatSessionManager,
  282. deps.sqLiteUserStore,
  283. nil,
  284. )
  285. chatService := foodgroup.NewChatService(deps.chatSessionManager)
  286. oServiceService := foodgroup.NewOServiceServiceForChat(
  287. deps.cfg,
  288. logger,
  289. sessionManager,
  290. deps.sqLiteUserStore,
  291. deps.chatSessionManager,
  292. deps.sqLiteUserStore,
  293. sessionManager,
  294. )
  295. return oscar.ChatServer{
  296. AuthService: authService,
  297. Config: deps.cfg,
  298. Handler: handler.NewChatRouter(handler.Handlers{
  299. ChatHandler: handler.NewChatHandler(logger, chatService),
  300. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  301. }),
  302. Logger: logger,
  303. OnlineNotifier: oServiceService,
  304. }
  305. }
  306. // ChatNav creates an OSCAR server for the ChatNav food group.
  307. func ChatNav(deps Container) oscar.BOSServer {
  308. logger := deps.logger.With("svc", "CHAT_NAV")
  309. sessionManager := state.NewInMemorySessionManager(logger)
  310. authService := foodgroup.NewAuthService(
  311. deps.cfg,
  312. sessionManager,
  313. deps.chatSessionManager,
  314. deps.sqLiteUserStore,
  315. deps.hmacCookieBaker,
  316. deps.chatSessionManager,
  317. deps.sqLiteUserStore,
  318. nil,
  319. )
  320. chatNavService := foodgroup.NewChatNavService(logger, deps.sqLiteUserStore)
  321. oServiceService := foodgroup.NewOServiceServiceForChatNav(
  322. deps.cfg,
  323. logger,
  324. sessionManager,
  325. deps.sqLiteUserStore,
  326. sessionManager,
  327. )
  328. return oscar.BOSServer{
  329. AuthService: authService,
  330. Config: deps.cfg,
  331. Handler: handler.NewChatNavRouter(handler.Handlers{
  332. ChatNavHandler: handler.NewChatNavHandler(chatNavService, logger),
  333. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  334. }),
  335. Logger: logger,
  336. OnlineNotifier: oServiceService,
  337. ListenAddr: net.JoinHostPort("", deps.cfg.ChatNavPort),
  338. }
  339. }
  340. // MgmtAPI creates an HTTP server for the management API.
  341. func MgmtAPI(deps Container) *http.Server {
  342. bld := config.Build{
  343. Version: version,
  344. Commit: commit,
  345. Date: date,
  346. }
  347. return http.NewManagementAPI(bld, deps.cfg, deps.sqLiteUserStore, deps.inMemorySessionManager, deps.sqLiteUserStore,
  348. deps.sqLiteUserStore, deps.chatSessionManager, deps.sqLiteUserStore, deps.inMemorySessionManager,
  349. deps.sqLiteUserStore, deps.sqLiteUserStore, deps.sqLiteUserStore, deps.sqLiteUserStore, deps.logger)
  350. }
  351. // ODir creates an OSCAR server for the ODir food group.
  352. func ODir(deps Container) oscar.BOSServer {
  353. logger := deps.logger.With("svc", "ODIR")
  354. sessionManager := state.NewInMemorySessionManager(logger)
  355. authService := foodgroup.NewAuthService(
  356. deps.cfg,
  357. sessionManager,
  358. deps.chatSessionManager,
  359. deps.sqLiteUserStore,
  360. deps.hmacCookieBaker,
  361. deps.chatSessionManager,
  362. deps.sqLiteUserStore,
  363. nil,
  364. )
  365. oServiceService := foodgroup.NewOServiceServiceForODir(deps.cfg, logger)
  366. oDirService := foodgroup.NewODirService(logger, deps.sqLiteUserStore)
  367. return oscar.BOSServer{
  368. AuthService: authService,
  369. Config: deps.cfg,
  370. Handler: handler.NewODirRouter(handler.Handlers{
  371. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  372. ODirHandler: handler.NewODirHandler(logger, oDirService),
  373. }),
  374. Logger: logger,
  375. OnlineNotifier: oServiceService,
  376. ListenAddr: net.JoinHostPort("", deps.cfg.ODirPort),
  377. }
  378. }
  379. // TOC creates a TOC server.
  380. func TOC(deps Container) toc.Server {
  381. logger := deps.logger.With("svc", "TOC")
  382. sessionManager := state.NewInMemorySessionManager(logger)
  383. return toc.Server{
  384. Logger: logger,
  385. ListenAddr: net.JoinHostPort(deps.cfg.TOCHost, deps.cfg.TOCPort),
  386. BOSProxy: toc.OSCARProxy{
  387. AdminService: foodgroup.NewAdminService(
  388. deps.sqLiteUserStore,
  389. deps.sqLiteUserStore,
  390. deps.inMemorySessionManager,
  391. deps.inMemorySessionManager,
  392. deps.logger,
  393. ),
  394. AuthService: foodgroup.NewAuthService(
  395. deps.cfg,
  396. deps.inMemorySessionManager,
  397. deps.chatSessionManager,
  398. deps.sqLiteUserStore,
  399. deps.hmacCookieBaker,
  400. deps.chatSessionManager,
  401. deps.sqLiteUserStore,
  402. nil,
  403. ),
  404. BuddyListRegistry: deps.sqLiteUserStore,
  405. BuddyService: foodgroup.NewBuddyService(
  406. deps.inMemorySessionManager,
  407. deps.sqLiteUserStore,
  408. deps.sqLiteUserStore,
  409. deps.inMemorySessionManager,
  410. ),
  411. CookieBaker: deps.hmacCookieBaker,
  412. DirSearchService: foodgroup.NewODirService(logger, deps.sqLiteUserStore),
  413. ICBMService: foodgroup.NewICBMService(
  414. deps.inMemorySessionManager,
  415. deps.sqLiteUserStore,
  416. deps.sqLiteUserStore,
  417. deps.inMemorySessionManager,
  418. ),
  419. LocateService: foodgroup.NewLocateService(
  420. deps.inMemorySessionManager,
  421. deps.sqLiteUserStore,
  422. deps.sqLiteUserStore,
  423. deps.inMemorySessionManager,
  424. ),
  425. Logger: logger,
  426. OServiceServiceBOS: foodgroup.NewOServiceServiceForBOS(
  427. deps.cfg,
  428. deps.inMemorySessionManager,
  429. logger,
  430. deps.hmacCookieBaker,
  431. deps.sqLiteUserStore,
  432. deps.sqLiteUserStore,
  433. deps.inMemorySessionManager,
  434. ),
  435. PermitDenyService: foodgroup.NewPermitDenyService(
  436. deps.sqLiteUserStore,
  437. deps.sqLiteUserStore,
  438. deps.inMemorySessionManager,
  439. deps.inMemorySessionManager,
  440. ),
  441. TOCConfigStore: deps.sqLiteUserStore,
  442. ChatService: foodgroup.NewChatService(deps.chatSessionManager),
  443. OServiceServiceChat: foodgroup.NewOServiceServiceForChat(
  444. deps.cfg,
  445. logger,
  446. sessionManager,
  447. deps.sqLiteUserStore,
  448. deps.chatSessionManager,
  449. deps.sqLiteUserStore,
  450. sessionManager,
  451. ),
  452. ChatNavService: foodgroup.NewChatNavService(logger, deps.sqLiteUserStore),
  453. },
  454. }
  455. }