factory.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  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. )
  60. authService := foodgroup.NewAuthService(
  61. deps.cfg,
  62. deps.inMemorySessionManager,
  63. deps.chatSessionManager,
  64. deps.sqLiteUserStore,
  65. deps.hmacCookieBaker,
  66. deps.chatSessionManager,
  67. deps.sqLiteUserStore,
  68. deps.inMemorySessionManager,
  69. )
  70. oServiceService := foodgroup.NewOServiceServiceForAdmin(
  71. deps.cfg,
  72. logger,
  73. deps.inMemorySessionManager,
  74. deps.sqLiteUserStore,
  75. deps.inMemorySessionManager,
  76. )
  77. return oscar.AdminServer{
  78. AuthService: authService,
  79. Config: deps.cfg,
  80. Handler: handler.NewAdminRouter(handler.Handlers{
  81. AdminHandler: handler.NewAdminHandler(logger, adminService),
  82. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  83. }),
  84. Logger: logger,
  85. OnlineNotifier: oServiceService,
  86. ListenAddr: net.JoinHostPort("", deps.cfg.AdminPort),
  87. }
  88. }
  89. // Alert creates an OSCAR server for the Alert food group.
  90. func Alert(deps Container) oscar.BOSServer {
  91. logger := deps.logger.With("svc", "ALERT")
  92. sessionManager := state.NewInMemorySessionManager(logger)
  93. authService := foodgroup.NewAuthService(
  94. deps.cfg,
  95. sessionManager,
  96. deps.chatSessionManager,
  97. deps.sqLiteUserStore,
  98. deps.hmacCookieBaker,
  99. deps.chatSessionManager,
  100. deps.sqLiteUserStore,
  101. nil,
  102. )
  103. oServiceService := foodgroup.NewOServiceServiceForAlert(
  104. deps.cfg,
  105. logger,
  106. sessionManager,
  107. deps.sqLiteUserStore,
  108. sessionManager,
  109. )
  110. return oscar.BOSServer{
  111. AuthService: authService,
  112. Config: deps.cfg,
  113. Handler: handler.NewAlertRouter(handler.Handlers{
  114. AlertHandler: handler.NewAlertHandler(logger),
  115. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  116. }),
  117. Logger: logger,
  118. OnlineNotifier: oServiceService,
  119. ListenAddr: net.JoinHostPort("", deps.cfg.AlertPort),
  120. }
  121. }
  122. // Auth creates an OSCAR server for the Auth food group.
  123. func Auth(deps Container) oscar.AuthServer {
  124. logger := deps.logger.With("svc", "AUTH")
  125. authHandler := foodgroup.NewAuthService(
  126. deps.cfg,
  127. deps.inMemorySessionManager,
  128. deps.chatSessionManager,
  129. deps.sqLiteUserStore,
  130. deps.hmacCookieBaker,
  131. deps.chatSessionManager,
  132. deps.sqLiteUserStore,
  133. nil,
  134. )
  135. return oscar.AuthServer{
  136. AuthService: authHandler,
  137. Config: deps.cfg,
  138. Logger: logger,
  139. }
  140. }
  141. // BART creates an OSCAR server for the BART food group.
  142. func BART(deps Container) oscar.BOSServer {
  143. logger := deps.logger.With("svc", "BART")
  144. sessionManager := state.NewInMemorySessionManager(logger)
  145. bartService := foodgroup.NewBARTService(
  146. logger,
  147. deps.sqLiteUserStore,
  148. sessionManager,
  149. deps.sqLiteUserStore,
  150. sessionManager,
  151. )
  152. authService := foodgroup.NewAuthService(
  153. deps.cfg,
  154. sessionManager,
  155. deps.chatSessionManager,
  156. deps.sqLiteUserStore,
  157. deps.hmacCookieBaker,
  158. deps.chatSessionManager,
  159. deps.sqLiteUserStore,
  160. nil,
  161. )
  162. oServiceService := foodgroup.NewOServiceServiceForBART(
  163. deps.cfg,
  164. logger,
  165. sessionManager,
  166. deps.sqLiteUserStore,
  167. sessionManager,
  168. )
  169. return oscar.BOSServer{
  170. AuthService: authService,
  171. Config: deps.cfg,
  172. Handler: handler.NewBARTRouter(handler.Handlers{
  173. BARTHandler: handler.NewBARTHandler(logger, bartService),
  174. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  175. }),
  176. ListenAddr: net.JoinHostPort("", deps.cfg.BARTPort),
  177. Logger: logger,
  178. OnlineNotifier: oServiceService,
  179. }
  180. }
  181. // BOS creates an OSCAR server for the BOS food group.
  182. func BOS(deps Container) oscar.BOSServer {
  183. logger := deps.logger.With("svc", "BOS")
  184. authService := foodgroup.NewAuthService(
  185. deps.cfg,
  186. deps.inMemorySessionManager,
  187. deps.chatSessionManager,
  188. deps.sqLiteUserStore,
  189. deps.hmacCookieBaker,
  190. deps.chatSessionManager,
  191. deps.sqLiteUserStore,
  192. nil,
  193. )
  194. bartService := foodgroup.NewBARTService(
  195. logger,
  196. deps.sqLiteUserStore,
  197. deps.inMemorySessionManager,
  198. deps.sqLiteUserStore,
  199. deps.inMemorySessionManager,
  200. )
  201. buddyService := foodgroup.NewBuddyService(
  202. deps.inMemorySessionManager,
  203. deps.sqLiteUserStore,
  204. deps.sqLiteUserStore,
  205. deps.inMemorySessionManager,
  206. )
  207. chatNavService := foodgroup.NewChatNavService(logger, deps.sqLiteUserStore)
  208. feedbagService := foodgroup.NewFeedbagService(
  209. logger,
  210. deps.inMemorySessionManager,
  211. deps.sqLiteUserStore,
  212. deps.sqLiteUserStore,
  213. deps.sqLiteUserStore,
  214. deps.inMemorySessionManager,
  215. )
  216. permitDenyService := foodgroup.NewPermitDenyService(
  217. deps.sqLiteUserStore,
  218. deps.sqLiteUserStore,
  219. deps.inMemorySessionManager,
  220. deps.inMemorySessionManager,
  221. )
  222. icbmService := foodgroup.NewICBMService(
  223. deps.inMemorySessionManager,
  224. deps.sqLiteUserStore,
  225. deps.sqLiteUserStore,
  226. deps.inMemorySessionManager,
  227. )
  228. icqService := foodgroup.NewICQService(deps.inMemorySessionManager, deps.sqLiteUserStore, deps.sqLiteUserStore,
  229. logger, deps.inMemorySessionManager, deps.sqLiteUserStore)
  230. locateService := foodgroup.NewLocateService(
  231. deps.inMemorySessionManager,
  232. deps.sqLiteUserStore,
  233. deps.sqLiteUserStore,
  234. deps.inMemorySessionManager,
  235. )
  236. oServiceService := foodgroup.NewOServiceServiceForBOS(
  237. deps.cfg,
  238. deps.inMemorySessionManager,
  239. logger,
  240. deps.hmacCookieBaker,
  241. deps.sqLiteUserStore,
  242. deps.sqLiteUserStore,
  243. deps.inMemorySessionManager,
  244. )
  245. userLookupService := foodgroup.NewUserLookupService(deps.sqLiteUserStore)
  246. return oscar.BOSServer{
  247. AuthService: authService,
  248. BuddyListRegistry: deps.sqLiteUserStore,
  249. Config: deps.cfg,
  250. DepartureNotifier: buddyService,
  251. Handler: handler.NewBOSRouter(handler.Handlers{
  252. AlertHandler: handler.NewAlertHandler(logger),
  253. BARTHandler: handler.NewBARTHandler(logger, bartService),
  254. BuddyHandler: handler.NewBuddyHandler(logger, buddyService),
  255. ChatNavHandler: handler.NewChatNavHandler(chatNavService, logger),
  256. FeedbagHandler: handler.NewFeedbagHandler(logger, feedbagService),
  257. ICQHandler: handler.NewICQHandler(logger, icqService),
  258. ICBMHandler: handler.NewICBMHandler(logger, icbmService),
  259. LocateHandler: handler.NewLocateHandler(locateService, logger),
  260. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  261. PermitDenyHandler: handler.NewPermitDenyHandler(logger, permitDenyService),
  262. UserLookupHandler: handler.NewUserLookupHandler(logger, userLookupService),
  263. }),
  264. Logger: logger,
  265. OnlineNotifier: oServiceService,
  266. ListenAddr: net.JoinHostPort("", deps.cfg.BOSPort),
  267. }
  268. }
  269. // Chat creates an OSCAR server for the Chat food group.
  270. func Chat(deps Container) oscar.ChatServer {
  271. logger := deps.logger.With("svc", "CHAT")
  272. sessionManager := state.NewInMemorySessionManager(logger)
  273. authService := foodgroup.NewAuthService(
  274. deps.cfg,
  275. sessionManager,
  276. deps.chatSessionManager,
  277. deps.sqLiteUserStore,
  278. deps.hmacCookieBaker,
  279. deps.chatSessionManager,
  280. deps.sqLiteUserStore,
  281. nil,
  282. )
  283. chatService := foodgroup.NewChatService(deps.chatSessionManager)
  284. oServiceService := foodgroup.NewOServiceServiceForChat(
  285. deps.cfg,
  286. logger,
  287. sessionManager,
  288. deps.sqLiteUserStore,
  289. deps.chatSessionManager,
  290. deps.sqLiteUserStore,
  291. sessionManager,
  292. )
  293. return oscar.ChatServer{
  294. AuthService: authService,
  295. Config: deps.cfg,
  296. Handler: handler.NewChatRouter(handler.Handlers{
  297. ChatHandler: handler.NewChatHandler(logger, chatService),
  298. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  299. }),
  300. Logger: logger,
  301. OnlineNotifier: oServiceService,
  302. }
  303. }
  304. // ChatNav creates an OSCAR server for the ChatNav food group.
  305. func ChatNav(deps Container) oscar.BOSServer {
  306. logger := deps.logger.With("svc", "CHAT_NAV")
  307. sessionManager := state.NewInMemorySessionManager(logger)
  308. authService := foodgroup.NewAuthService(
  309. deps.cfg,
  310. sessionManager,
  311. deps.chatSessionManager,
  312. deps.sqLiteUserStore,
  313. deps.hmacCookieBaker,
  314. deps.chatSessionManager,
  315. deps.sqLiteUserStore,
  316. nil,
  317. )
  318. chatNavService := foodgroup.NewChatNavService(logger, deps.sqLiteUserStore)
  319. oServiceService := foodgroup.NewOServiceServiceForChatNav(
  320. deps.cfg,
  321. logger,
  322. sessionManager,
  323. deps.sqLiteUserStore,
  324. sessionManager,
  325. )
  326. return oscar.BOSServer{
  327. AuthService: authService,
  328. Config: deps.cfg,
  329. Handler: handler.NewChatNavRouter(handler.Handlers{
  330. ChatNavHandler: handler.NewChatNavHandler(chatNavService, logger),
  331. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  332. }),
  333. Logger: logger,
  334. OnlineNotifier: oServiceService,
  335. ListenAddr: net.JoinHostPort("", deps.cfg.ChatNavPort),
  336. }
  337. }
  338. // MgmtAPI creates an HTTP server for the management API.
  339. func MgmtAPI(deps Container) *http.Server {
  340. bld := config.Build{
  341. Version: version,
  342. Commit: commit,
  343. Date: date,
  344. }
  345. return http.NewManagementAPI(bld, deps.cfg, deps.sqLiteUserStore, deps.inMemorySessionManager, deps.sqLiteUserStore,
  346. deps.sqLiteUserStore, deps.chatSessionManager, deps.sqLiteUserStore, deps.inMemorySessionManager,
  347. deps.sqLiteUserStore, deps.sqLiteUserStore, deps.sqLiteUserStore, deps.sqLiteUserStore, deps.logger)
  348. }
  349. // ODir creates an OSCAR server for the ODir food group.
  350. func ODir(deps Container) oscar.BOSServer {
  351. logger := deps.logger.With("svc", "ODIR")
  352. sessionManager := state.NewInMemorySessionManager(logger)
  353. authService := foodgroup.NewAuthService(
  354. deps.cfg,
  355. sessionManager,
  356. deps.chatSessionManager,
  357. deps.sqLiteUserStore,
  358. deps.hmacCookieBaker,
  359. deps.chatSessionManager,
  360. deps.sqLiteUserStore,
  361. nil,
  362. )
  363. oServiceService := foodgroup.NewOServiceServiceForODir(deps.cfg, logger)
  364. oDirService := foodgroup.NewODirService(logger, deps.sqLiteUserStore)
  365. return oscar.BOSServer{
  366. AuthService: authService,
  367. Config: deps.cfg,
  368. Handler: handler.NewODirRouter(handler.Handlers{
  369. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  370. ODirHandler: handler.NewODirHandler(logger, oDirService),
  371. }),
  372. Logger: logger,
  373. OnlineNotifier: oServiceService,
  374. ListenAddr: net.JoinHostPort("", deps.cfg.ODirPort),
  375. }
  376. }
  377. // TOC creates a TOC server.
  378. func TOC(deps Container) toc.Server {
  379. logger := deps.logger.With("svc", "TOC")
  380. sessionManager := state.NewInMemorySessionManager(logger)
  381. return toc.Server{
  382. Logger: logger,
  383. ListenAddr: net.JoinHostPort(deps.cfg.TOCHost, deps.cfg.TOCPort),
  384. BOSProxy: toc.OSCARProxy{
  385. AuthService: foodgroup.NewAuthService(
  386. deps.cfg,
  387. deps.inMemorySessionManager,
  388. deps.chatSessionManager,
  389. deps.sqLiteUserStore,
  390. deps.hmacCookieBaker,
  391. deps.chatSessionManager,
  392. deps.sqLiteUserStore,
  393. nil,
  394. ),
  395. BuddyListRegistry: deps.sqLiteUserStore,
  396. BuddyService: foodgroup.NewBuddyService(
  397. deps.inMemorySessionManager,
  398. deps.sqLiteUserStore,
  399. deps.sqLiteUserStore,
  400. deps.inMemorySessionManager,
  401. ),
  402. CookieBaker: deps.hmacCookieBaker,
  403. DirSearchService: foodgroup.NewODirService(logger, deps.sqLiteUserStore),
  404. ICBMService: foodgroup.NewICBMService(
  405. deps.inMemorySessionManager,
  406. deps.sqLiteUserStore,
  407. deps.sqLiteUserStore,
  408. deps.inMemorySessionManager,
  409. ),
  410. LocateService: foodgroup.NewLocateService(
  411. deps.inMemorySessionManager,
  412. deps.sqLiteUserStore,
  413. deps.sqLiteUserStore,
  414. deps.inMemorySessionManager,
  415. ),
  416. Logger: logger,
  417. OServiceServiceBOS: foodgroup.NewOServiceServiceForBOS(
  418. deps.cfg,
  419. deps.inMemorySessionManager,
  420. logger,
  421. deps.hmacCookieBaker,
  422. deps.sqLiteUserStore,
  423. deps.sqLiteUserStore,
  424. deps.inMemorySessionManager,
  425. ),
  426. PermitDenyService: foodgroup.NewPermitDenyService(
  427. deps.sqLiteUserStore,
  428. deps.sqLiteUserStore,
  429. deps.inMemorySessionManager,
  430. deps.inMemorySessionManager,
  431. ),
  432. TOCConfigStore: deps.sqLiteUserStore,
  433. ChatService: foodgroup.NewChatService(deps.chatSessionManager),
  434. OServiceServiceChat: foodgroup.NewOServiceServiceForChat(
  435. deps.cfg,
  436. logger,
  437. sessionManager,
  438. deps.sqLiteUserStore,
  439. deps.chatSessionManager,
  440. deps.sqLiteUserStore,
  441. sessionManager,
  442. ),
  443. ChatNavService: foodgroup.NewChatNavService(logger, deps.sqLiteUserStore),
  444. },
  445. }
  446. }