factory.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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. ChatSessionManager: deps.chatSessionManager,
  252. Handler: handler.NewBOSRouter(handler.Handlers{
  253. AlertHandler: handler.NewAlertHandler(logger),
  254. BARTHandler: handler.NewBARTHandler(logger, bartService),
  255. BuddyHandler: handler.NewBuddyHandler(logger, buddyService),
  256. ChatNavHandler: handler.NewChatNavHandler(chatNavService, logger),
  257. FeedbagHandler: handler.NewFeedbagHandler(logger, feedbagService),
  258. ICQHandler: handler.NewICQHandler(logger, icqService),
  259. ICBMHandler: handler.NewICBMHandler(logger, icbmService),
  260. LocateHandler: handler.NewLocateHandler(locateService, logger),
  261. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  262. PermitDenyHandler: handler.NewPermitDenyHandler(logger, permitDenyService),
  263. UserLookupHandler: handler.NewUserLookupHandler(logger, userLookupService),
  264. }),
  265. Logger: logger,
  266. OnlineNotifier: oServiceService,
  267. ListenAddr: net.JoinHostPort("", deps.cfg.BOSPort),
  268. }
  269. }
  270. // Chat creates an OSCAR server for the Chat food group.
  271. func Chat(deps Container) oscar.ChatServer {
  272. logger := deps.logger.With("svc", "CHAT")
  273. sessionManager := state.NewInMemorySessionManager(logger)
  274. authService := foodgroup.NewAuthService(
  275. deps.cfg,
  276. sessionManager,
  277. deps.chatSessionManager,
  278. deps.sqLiteUserStore,
  279. deps.hmacCookieBaker,
  280. deps.chatSessionManager,
  281. deps.sqLiteUserStore,
  282. nil,
  283. )
  284. chatService := foodgroup.NewChatService(deps.chatSessionManager)
  285. oServiceService := foodgroup.NewOServiceServiceForChat(
  286. deps.cfg,
  287. logger,
  288. sessionManager,
  289. deps.sqLiteUserStore,
  290. deps.chatSessionManager,
  291. deps.sqLiteUserStore,
  292. sessionManager,
  293. )
  294. return oscar.ChatServer{
  295. AuthService: authService,
  296. Config: deps.cfg,
  297. Handler: handler.NewChatRouter(handler.Handlers{
  298. ChatHandler: handler.NewChatHandler(logger, chatService),
  299. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  300. }),
  301. Logger: logger,
  302. OnlineNotifier: oServiceService,
  303. }
  304. }
  305. // ChatNav creates an OSCAR server for the ChatNav food group.
  306. func ChatNav(deps Container) oscar.BOSServer {
  307. logger := deps.logger.With("svc", "CHAT_NAV")
  308. sessionManager := state.NewInMemorySessionManager(logger)
  309. authService := foodgroup.NewAuthService(
  310. deps.cfg,
  311. sessionManager,
  312. deps.chatSessionManager,
  313. deps.sqLiteUserStore,
  314. deps.hmacCookieBaker,
  315. deps.chatSessionManager,
  316. deps.sqLiteUserStore,
  317. nil,
  318. )
  319. chatNavService := foodgroup.NewChatNavService(logger, deps.sqLiteUserStore)
  320. oServiceService := foodgroup.NewOServiceServiceForChatNav(
  321. deps.cfg,
  322. logger,
  323. sessionManager,
  324. deps.sqLiteUserStore,
  325. sessionManager,
  326. )
  327. return oscar.BOSServer{
  328. AuthService: authService,
  329. Config: deps.cfg,
  330. Handler: handler.NewChatNavRouter(handler.Handlers{
  331. ChatNavHandler: handler.NewChatNavHandler(chatNavService, logger),
  332. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  333. }),
  334. Logger: logger,
  335. OnlineNotifier: oServiceService,
  336. ListenAddr: net.JoinHostPort("", deps.cfg.ChatNavPort),
  337. }
  338. }
  339. // MgmtAPI creates an HTTP server for the management API.
  340. func MgmtAPI(deps Container) *http.Server {
  341. bld := config.Build{
  342. Version: version,
  343. Commit: commit,
  344. Date: date,
  345. }
  346. return http.NewManagementAPI(bld, deps.cfg, deps.sqLiteUserStore, deps.inMemorySessionManager, deps.sqLiteUserStore,
  347. deps.sqLiteUserStore, deps.chatSessionManager, deps.sqLiteUserStore, deps.inMemorySessionManager,
  348. deps.sqLiteUserStore, deps.sqLiteUserStore, deps.sqLiteUserStore, deps.sqLiteUserStore, deps.logger)
  349. }
  350. // ODir creates an OSCAR server for the ODir food group.
  351. func ODir(deps Container) oscar.BOSServer {
  352. logger := deps.logger.With("svc", "ODIR")
  353. sessionManager := state.NewInMemorySessionManager(logger)
  354. authService := foodgroup.NewAuthService(
  355. deps.cfg,
  356. sessionManager,
  357. deps.chatSessionManager,
  358. deps.sqLiteUserStore,
  359. deps.hmacCookieBaker,
  360. deps.chatSessionManager,
  361. deps.sqLiteUserStore,
  362. nil,
  363. )
  364. oServiceService := foodgroup.NewOServiceServiceForODir(deps.cfg, logger)
  365. oDirService := foodgroup.NewODirService(logger, deps.sqLiteUserStore)
  366. return oscar.BOSServer{
  367. AuthService: authService,
  368. Config: deps.cfg,
  369. Handler: handler.NewODirRouter(handler.Handlers{
  370. OServiceHandler: handler.NewOServiceHandler(logger, oServiceService),
  371. ODirHandler: handler.NewODirHandler(logger, oDirService),
  372. }),
  373. Logger: logger,
  374. OnlineNotifier: oServiceService,
  375. ListenAddr: net.JoinHostPort("", deps.cfg.ODirPort),
  376. }
  377. }
  378. // TOC creates a TOC server.
  379. func TOC(deps Container) toc.Server {
  380. logger := deps.logger.With("svc", "TOC")
  381. sessionManager := state.NewInMemorySessionManager(logger)
  382. return toc.Server{
  383. Logger: logger,
  384. ListenAddr: net.JoinHostPort(deps.cfg.TOCHost, deps.cfg.TOCPort),
  385. BOSProxy: toc.OSCARProxy{
  386. AuthService: foodgroup.NewAuthService(
  387. deps.cfg,
  388. deps.inMemorySessionManager,
  389. deps.chatSessionManager,
  390. deps.sqLiteUserStore,
  391. deps.hmacCookieBaker,
  392. deps.chatSessionManager,
  393. deps.sqLiteUserStore,
  394. nil,
  395. ),
  396. BuddyListRegistry: deps.sqLiteUserStore,
  397. BuddyService: foodgroup.NewBuddyService(
  398. deps.inMemorySessionManager,
  399. deps.sqLiteUserStore,
  400. deps.sqLiteUserStore,
  401. deps.inMemorySessionManager,
  402. ),
  403. CookieBaker: deps.hmacCookieBaker,
  404. DirSearchService: foodgroup.NewODirService(logger, deps.sqLiteUserStore),
  405. ICBMService: foodgroup.NewICBMService(
  406. deps.inMemorySessionManager,
  407. deps.sqLiteUserStore,
  408. deps.sqLiteUserStore,
  409. deps.inMemorySessionManager,
  410. ),
  411. LocateService: foodgroup.NewLocateService(
  412. deps.inMemorySessionManager,
  413. deps.sqLiteUserStore,
  414. deps.sqLiteUserStore,
  415. deps.inMemorySessionManager,
  416. ),
  417. Logger: logger,
  418. OServiceServiceBOS: foodgroup.NewOServiceServiceForBOS(
  419. deps.cfg,
  420. deps.inMemorySessionManager,
  421. logger,
  422. deps.hmacCookieBaker,
  423. deps.sqLiteUserStore,
  424. deps.sqLiteUserStore,
  425. deps.inMemorySessionManager,
  426. ),
  427. PermitDenyService: foodgroup.NewPermitDenyService(
  428. deps.sqLiteUserStore,
  429. deps.sqLiteUserStore,
  430. deps.inMemorySessionManager,
  431. deps.inMemorySessionManager,
  432. ),
  433. TOCConfigStore: deps.sqLiteUserStore,
  434. ChatService: foodgroup.NewChatService(deps.chatSessionManager),
  435. OServiceServiceChat: foodgroup.NewOServiceServiceForChat(
  436. deps.cfg,
  437. logger,
  438. sessionManager,
  439. deps.sqLiteUserStore,
  440. deps.chatSessionManager,
  441. deps.sqLiteUserStore,
  442. sessionManager,
  443. ),
  444. ChatNavService: foodgroup.NewChatNavService(logger, deps.sqLiteUserStore),
  445. },
  446. }
  447. }