@social-mail/social-mail-web-server 1.7.232 → 1.7.233

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/WebServer.d.ts.map +1 -1
  2. package/dist/WebServer.js +0 -2
  3. package/dist/WebServer.js.map +1 -1
  4. package/dist/common/GlobalEvents.d.ts +1 -47
  5. package/dist/common/GlobalEvents.d.ts.map +1 -1
  6. package/dist/common/GlobalEvents.js +231 -243
  7. package/dist/common/GlobalEvents.js.map +1 -1
  8. package/dist/common/globalEnv.d.ts +9 -0
  9. package/dist/common/globalEnv.d.ts.map +1 -1
  10. package/dist/common/globalEnv.js +9 -0
  11. package/dist/common/globalEnv.js.map +1 -1
  12. package/dist/server/model/events/DomainKeyEvents.d.ts +0 -1
  13. package/dist/server/model/events/DomainKeyEvents.d.ts.map +1 -1
  14. package/dist/server/model/events/DomainKeyEvents.js +0 -5
  15. package/dist/server/model/events/DomainKeyEvents.js.map +1 -1
  16. package/dist/server/model/events/WebSiteHostEvents.d.ts +0 -1
  17. package/dist/server/model/events/WebSiteHostEvents.d.ts.map +1 -1
  18. package/dist/server/model/events/WebSiteHostEvents.js +1 -15
  19. package/dist/server/model/events/WebSiteHostEvents.js.map +1 -1
  20. package/dist/server/services/message-events/MessagingService.d.ts +17 -0
  21. package/dist/server/services/message-events/MessagingService.d.ts.map +1 -0
  22. package/dist/server/services/message-events/MessagingService.js +42 -0
  23. package/dist/server/services/message-events/MessagingService.js.map +1 -0
  24. package/dist/server/services/message-events/PgEvents.d.ts +13 -0
  25. package/dist/server/services/message-events/PgEvents.d.ts.map +1 -0
  26. package/dist/server/services/message-events/PgEvents.js +215 -0
  27. package/dist/server/services/message-events/PgEvents.js.map +1 -0
  28. package/dist/server/smtp/services/WebSiteChannelService.d.ts +0 -2
  29. package/dist/server/smtp/services/WebSiteChannelService.d.ts.map +1 -1
  30. package/dist/server/smtp/services/WebSiteChannelService.js +6 -20
  31. package/dist/server/smtp/services/WebSiteChannelService.js.map +1 -1
  32. package/dist/server/workflows/dns/SyncDnsZoneRecordsWorkflow.d.ts +2 -2
  33. package/dist/server/workflows/dns/SyncDnsZoneRecordsWorkflow.d.ts.map +1 -1
  34. package/dist/server/workflows/dns/SyncDnsZoneRecordsWorkflow.js +4 -4
  35. package/dist/server/workflows/dns/SyncDnsZoneRecordsWorkflow.js.map +1 -1
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +3 -3
  38. package/src/WebServer.ts +0 -3
  39. package/src/common/GlobalEvents.ts +249 -249
  40. package/src/common/globalEnv.ts +11 -0
  41. package/src/server/model/events/DomainKeyEvents.ts +0 -5
  42. package/src/server/model/events/WebSiteHostEvents.ts +0 -4
  43. package/src/server/services/message-events/MessagingService.ts +43 -0
  44. package/src/server/services/message-events/PgEvents.ts +153 -0
  45. package/src/server/smtp/services/WebSiteChannelService.ts +5 -22
  46. package/src/server/workflows/dns/SyncDnsZoneRecordsWorkflow.ts +3 -3
@@ -0,0 +1,153 @@
1
+ /* eslint-disable no-console */
2
+ import Inject, { RegisterSingleton } from "@entity-access/entity-access/dist/di/di.js";
3
+ import pg from "pg";
4
+ import sleep from "../../../common/sleep.js";
5
+ import { globalEnv } from "../../../common/globalEnv.js";
6
+ import LockFile from "../../storage/LockFile.js";
7
+
8
+ export type messageTypes = string;
9
+
10
+ @RegisterSingleton
11
+ export default class PgEvents {
12
+
13
+
14
+ private _client: Promise<pg.Client>;
15
+ private _running: Promise<any>;
16
+
17
+ private handlers: Map<string,{ original: messageTypes, listening: boolean, handler: (message: messageTypes, payload) => any}[]> = new Map();
18
+ private added: string[] = [];
19
+ private removed: string[] = [];
20
+
21
+ private get client() {
22
+ return this._client ??= (async () => {
23
+ try {
24
+ const c = new pg.Client(globalEnv.pgEvents);
25
+ await c.connect();
26
+ c.on("error", () => {
27
+ try {
28
+ c.end().catch(console.error);
29
+ } catch (error) {
30
+ console.error(error);
31
+ }
32
+ this._client = null;
33
+ });
34
+ c.on("end", () => this._client = null);
35
+ c.on("notification", async ({ channel, payload}) => {
36
+ try {
37
+ console.log(`Notification received ${channel}`);
38
+ const fx = this.handlers.get(channel);
39
+ if (fx) {
40
+ for (const { original, handler } of fx) {
41
+ try {
42
+ const p = handler(original as any, JSON.parse(payload));
43
+ if (p?.then) {
44
+ p.catch(console.error);
45
+ }
46
+ } catch (e) {
47
+ console.error(e);
48
+ }
49
+ }
50
+ }
51
+ } catch (error) {
52
+ console.error(error);
53
+ }
54
+ });
55
+ return c;
56
+ } catch (error) {
57
+ console.error(error);
58
+ }
59
+ })();
60
+ }
61
+
62
+ async emit(message: messageTypes, payload) {
63
+ /**
64
+ * Improve sending messages by queueing
65
+ */
66
+ try {
67
+ let lastError = null;
68
+ for(let i=0;i<10;i++) {
69
+
70
+ // locking queue messages
71
+ using fx = await LockFile.lock(`pg-events-msg${message}`);
72
+
73
+ const id = "social_" + message.replace(/[^a-zA-Z0-9]/g, "_");
74
+ const c = new pg.Client(globalEnv.pgEvents);
75
+ try {
76
+ await c.connect();
77
+ await c.query("select pg_notify($1,$2)", [ id, JSON.stringify(payload || null)]);
78
+ break;
79
+ } catch (e) {
80
+ lastError = e;
81
+ continue;
82
+ } finally {
83
+ await c.end();
84
+ }
85
+ }
86
+ if (lastError) {
87
+ console.error(lastError);
88
+ }
89
+ } catch (error) {
90
+ console.error(error);
91
+ }
92
+ }
93
+
94
+ async listen(message: messageTypes, fx: (msg: messageTypes, payload: any) => any): Promise<AsyncDisposable> {
95
+
96
+ const id = "social_" + message.replace(/[^a-zA-Z0-9]/g, "_");
97
+ let handlers = this.handlers.get(id);
98
+ if(!handlers) {
99
+ handlers = [];
100
+ this.handlers.set(id, handlers);
101
+ }
102
+ handlers.push({ original: message, listening: false, handler: fx });
103
+ // client.query(`LISTEN ${id}`).catch(console.error);
104
+ console.log(`Listening for ${message} as ${id} on pg`);
105
+ this.added.push(id);
106
+ this.update().catch(console.error);
107
+ return {
108
+ [Symbol.asyncDispose]: async () => {
109
+ try {
110
+ this.handlers.delete(id);
111
+ this.removed.push(id);
112
+ this.update().catch(console.error);
113
+ } catch (error) {
114
+ console.warn(error);
115
+ }
116
+ }
117
+ };
118
+ }
119
+
120
+ private update() {
121
+ return this._running ??= (async () => {
122
+ while(this.handlers.size) {
123
+ try {
124
+ const c = await this.client;
125
+ if (!c) {
126
+ await sleep(3000);
127
+ continue;
128
+ }
129
+ if (this.added.length) {
130
+ const added = [... this.added];
131
+ this.added.length = 0;
132
+ for (const iterator of added) {
133
+ await c.query(`LISTEN ${iterator};`);
134
+ }
135
+ }
136
+ if (this.removed.length) {
137
+ const removed = [... this.removed];
138
+ this.removed.length = 0;
139
+ for (const iterator of removed) {
140
+ await c.query(`UNLISTEN ${iterator};`);
141
+ }
142
+ }
143
+ await c.query("select 1;");
144
+ } catch (error) {
145
+ console.error(error);
146
+ }
147
+ await sleep(30000);
148
+ }
149
+ this._running = null;
150
+ })();
151
+ }
152
+
153
+ }
@@ -1,32 +1,13 @@
1
1
 
2
2
  import Inject, { RegisterScoped, RegisterSingleton, RegisterTransient, ServiceCollection, ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
3
3
  import SocialMailContext from "../../model/SocialMailContext.js";
4
- import GlobalEvents from "../../../common/GlobalEvents.js";
5
4
  import { cacheFor, ICacheContainer, ObjectCache } from "../../../common/cacheFor.js";
5
+ import MessagingService from "../../services/message-events/MessagingService.js";
6
6
 
7
7
  export default class WebSiteChannelService implements ICacheContainer<WebSiteChannelService> {
8
8
 
9
9
  cache: ObjectCache<WebSiteChannelService>;
10
10
 
11
- @Inject
12
- globalEvents: GlobalEvents;
13
-
14
- // @cacheFor()
15
- // async getMailboxes(host: string) {
16
- // using scope = ServiceProvider.createScope(this);
17
- // const db = scope.resolve(SocialMailContext);
18
-
19
- // host = host?.toLocaleLowerCase() ?? "localhost";
20
-
21
- // const mailboxes = await db.mailboxes.where({ host}, (p) => (x) =>
22
- // x.websiteChannels
23
- // .some((w) => w.website.hosts
24
- // .some((h)=> h.host === p.host)))
25
- // .toArray();
26
-
27
- // return mailboxes.map((x) => x.mailboxID);
28
- // }
29
-
30
11
  @cacheFor()
31
12
  async getChannelAssociations(host: string) {
32
13
  using scope = ServiceProvider.createScope(this);
@@ -57,11 +38,13 @@ export default class WebSiteChannelService implements ICacheContainer<WebSiteCha
57
38
  }
58
39
 
59
40
  clear() {
60
- this.globalEvents.notify("web-site-channel-host-clear" as any, {} as any);
41
+ const ms = ServiceProvider.resolve(this, MessagingService).channelRefresh;
42
+ ms.notify("clear");
61
43
  }
62
44
 
63
45
  protected postInit() {
64
- this.globalEvents.on("web-site-channel-host-clear" as any, () => this.cache?.clear("getChannelAssociations") );
46
+ const ms = ServiceProvider.resolve(this, MessagingService).channelRefresh;
47
+ ms.on(() => this.cache?.clear("getChannelAssociations") );
65
48
  }
66
49
 
67
50
  }
@@ -6,8 +6,8 @@ import SocialMailContext from "../../model/SocialMailContext.js";
6
6
  import EmailAddressService from "../../services/EmailAddressService.js";
7
7
  import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
8
8
  import { globalEnv } from "../../../common/globalEnv.js";
9
- import GlobalEvents from "../../../common/GlobalEvents.js";
10
9
  import StringFormat from "../../../common/StringFormat.js";
10
+ import MessagingService from "../../services/message-events/MessagingService.js";
11
11
 
12
12
  const toUnixDateAndHour = (date: Date | DateTime, d = DateTime.from(date)) =>
13
13
  `${StringFormat.fixed(d.year, 4)}${StringFormat.fixed(d.month)}${StringFormat.fixed(d.day)}${StringFormat.fixed(d.hour)}`;
@@ -35,11 +35,11 @@ export default class SyncDnsZoneRecordsWorkflow extends Workflow {
35
35
  @UniqueActivity
36
36
  async notifyDns(
37
37
  @Inject db?: SocialMailContext,
38
- @Inject ge?: GlobalEvents
38
+ @Inject ms?: MessagingService
39
39
  ) {
40
40
  const zoneID = this.input;
41
41
  await db.hostedZones.statements.update({ dateSigned: null, dateUpdated: DateTime.now }, { zoneID });
42
- ge.notify("refresh-dns", { serverID: globalEnv.serverID });
42
+ ms.refreshDns.notify({ serverID: globalEnv.serverID });
43
43
  }
44
44
 
45
45
  @UniqueActivity