feat(wire): Add wire protocol, WireTarget & WireParser, Smartmail JSON serialization; refactor plugins and update dependencies
This commit is contained in:
252
ts/smartmail.classes.wireparser.ts
Normal file
252
ts/smartmail.classes.wireparser.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import { Smartmail } from './smartmail.classes.smartmail.js';
|
||||
import {
|
||||
type IWireMessage,
|
||||
type IMailSendRequest,
|
||||
type IMailSendResponse,
|
||||
type IMailboxListRequest,
|
||||
type IMailboxListResponse,
|
||||
type IMailFetchRequest,
|
||||
type IMailFetchResponse,
|
||||
type IMailStatusRequest,
|
||||
type IMailStatusResponse,
|
||||
type ISettingsUpdateRequest,
|
||||
type ISettingsUpdateResponse,
|
||||
type IWireSettings,
|
||||
type TWireMessage,
|
||||
createMessageId,
|
||||
createTimestamp,
|
||||
} from './smartmail.wire.js';
|
||||
|
||||
/**
|
||||
* Handler functions for different wire message types
|
||||
*/
|
||||
export interface IWireHandlers {
|
||||
/** Handler for mail send requests */
|
||||
onMailSend?: (
|
||||
email: Smartmail<any>,
|
||||
options?: IMailSendRequest['options']
|
||||
) => Promise<IMailSendResponse>;
|
||||
|
||||
/** Handler for mailbox list requests */
|
||||
onMailboxList?: (
|
||||
mailbox: string,
|
||||
options?: { limit?: number; offset?: number }
|
||||
) => Promise<IMailboxListResponse>;
|
||||
|
||||
/** Handler for mail fetch requests */
|
||||
onMailFetch?: (mailbox: string, emailId: string) => Promise<IMailFetchResponse>;
|
||||
|
||||
/** Handler for mail status requests */
|
||||
onMailStatus?: (deliveryId: string) => Promise<IMailStatusResponse>;
|
||||
|
||||
/** Handler for settings update requests */
|
||||
onSettingsUpdate?: (settings: IWireSettings) => Promise<ISettingsUpdateResponse>;
|
||||
}
|
||||
|
||||
/**
|
||||
* WireParser is used by the SMTP service to parse and handle incoming wire messages.
|
||||
* It provides a handler-based approach for processing different message types.
|
||||
*/
|
||||
export class WireParser {
|
||||
private handlers: IWireHandlers;
|
||||
|
||||
constructor(handlers: IWireHandlers = {}) {
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a wire message from JSON string
|
||||
* @param json The JSON string to parse
|
||||
* @returns Parsed wire message
|
||||
*/
|
||||
public parse(json: string): TWireMessage {
|
||||
return JSON.parse(json) as TWireMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming wire message and return the response
|
||||
* @param message The wire message to handle
|
||||
* @returns Promise resolving to the response message
|
||||
*/
|
||||
public async handle(message: TWireMessage): Promise<IWireMessage> {
|
||||
switch (message.type) {
|
||||
case 'mail.send':
|
||||
return this.handleMailSend(message);
|
||||
case 'mailbox.list':
|
||||
return this.handleMailboxList(message);
|
||||
case 'mail.fetch':
|
||||
return this.handleMailFetch(message);
|
||||
case 'mail.status':
|
||||
return this.handleMailStatus(message);
|
||||
case 'settings.update':
|
||||
return this.handleSettingsUpdate(message);
|
||||
default:
|
||||
return this.createErrorResponse(message, 'Unknown message type');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and handle in one step (convenience method)
|
||||
* @param json The JSON string to parse and handle
|
||||
* @returns Promise resolving to JSON response string
|
||||
*/
|
||||
public async parseAndHandle(json: string): Promise<string> {
|
||||
const message = this.parse(json);
|
||||
const response = await this.handle(message);
|
||||
return JSON.stringify(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mail send request
|
||||
*/
|
||||
private async handleMailSend(message: IMailSendRequest): Promise<IMailSendResponse> {
|
||||
if (!this.handlers.onMailSend) {
|
||||
return {
|
||||
type: 'mail.send.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
success: false,
|
||||
error: 'Mail send not supported',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const email = Smartmail.fromObject(message.email);
|
||||
return await this.handlers.onMailSend(email, message.options);
|
||||
} catch (error) {
|
||||
return {
|
||||
type: 'mail.send.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mailbox list request
|
||||
*/
|
||||
private async handleMailboxList(message: IMailboxListRequest): Promise<IMailboxListResponse> {
|
||||
if (!this.handlers.onMailboxList) {
|
||||
return {
|
||||
type: 'mailbox.list.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
mailbox: message.mailbox,
|
||||
emails: [],
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.handlers.onMailboxList(message.mailbox, {
|
||||
limit: message.limit,
|
||||
offset: message.offset,
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
type: 'mailbox.list.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
mailbox: message.mailbox,
|
||||
emails: [],
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mail fetch request
|
||||
*/
|
||||
private async handleMailFetch(message: IMailFetchRequest): Promise<IMailFetchResponse> {
|
||||
if (!this.handlers.onMailFetch) {
|
||||
return {
|
||||
type: 'mail.fetch.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
email: null,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.handlers.onMailFetch(message.mailbox, message.emailId);
|
||||
} catch (error) {
|
||||
return {
|
||||
type: 'mail.fetch.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
email: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mail status request
|
||||
*/
|
||||
private async handleMailStatus(message: IMailStatusRequest): Promise<IMailStatusResponse> {
|
||||
if (!this.handlers.onMailStatus) {
|
||||
return {
|
||||
type: 'mail.status.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
deliveryId: message.deliveryId,
|
||||
status: 'failed',
|
||||
error: 'Mail status not supported',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.handlers.onMailStatus(message.deliveryId);
|
||||
} catch (error) {
|
||||
return {
|
||||
type: 'mail.status.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
deliveryId: message.deliveryId,
|
||||
status: 'failed',
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle settings update request
|
||||
*/
|
||||
private async handleSettingsUpdate(
|
||||
message: ISettingsUpdateRequest
|
||||
): Promise<ISettingsUpdateResponse> {
|
||||
if (!this.handlers.onSettingsUpdate) {
|
||||
return {
|
||||
type: 'settings.update.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
success: false,
|
||||
error: 'Settings update not supported',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.handlers.onSettingsUpdate(message.settings);
|
||||
} catch (error) {
|
||||
return {
|
||||
type: 'settings.update.response',
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error response for unknown message types
|
||||
*/
|
||||
private createErrorResponse(message: IWireMessage, error: string): IWireMessage {
|
||||
return {
|
||||
type: `${message.type}.response`,
|
||||
messageId: message.messageId,
|
||||
timestamp: createTimestamp(),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user