Skip to content

Commit

Permalink
feat: switch to URL handler for processor registration
Browse files Browse the repository at this point in the history
  • Loading branch information
npenin committed Jan 30, 2024
1 parent 1a9608f commit 341872b
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 97 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"**/node_modules/*/**": true
},
"sync.quietSync": true,
"debug.javascript.autoAttachFilter": "smart",
"debug.javascript.autoAttachFilter": "always",
"liveshare.connectionMode": "relay",
"editor.suggestSelection": "first",
"vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
Expand Down
14 changes: 10 additions & 4 deletions packages/commands/src/akala.mts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { program as root, ErrorMessage, NamespaceMiddleware } from "@akala/cli"
import { Injector, mapAsync } from "@akala/core"
import commands from "./commands.js";
import { Cli, ServeOptions, registerCommands } from "./index.js";
import { Cli, ICommandProcessor, ServeOptions, registerCommands } from "./index.js";
import { Container } from "./model/container.js";
import $serve from "./commands/$serve.js";
import { Configurations } from "./metadata/configurations.js";
import getHandler, { getHandlers } from "./protocol-handler.js";
import { dirname, isAbsolute, resolve } from "node:path";
import { Local } from "./processors/local.js";
import { HandlerResult, handlers } from "./protocol-handler.js";
const serveDefinition: Configurations = await import('../' + '../src/commands/$serve.json', { assert: { type: 'json' } }).then(x => x.default)

export default function (config, program: NamespaceMiddleware<{ configFile: string }>)
Expand Down Expand Up @@ -40,7 +40,10 @@ export default function (config, program: NamespaceMiddleware<{ configFile: stri
uri = new URL('file://' + path);
}
}
const handler = await getHandler(uri.protocol, uri)
let handler: HandlerResult<ICommandProcessor> = {
processor: null, getMetadata() { return Promise.resolve(null) }
};
await handlers.process(uri, handler)

cliContainer.processor.useMiddleware(51, handler.processor);

Expand Down Expand Up @@ -80,10 +83,13 @@ export default function (config, program: NamespaceMiddleware<{ configFile: stri
try
{
const url = new URL(context.options.path);
getHandlers(url.protocol.substring(0, url.protocol.length - 1))
handlers.protocol.process(url, { processor: null, getMetadata: () => void 0 })
console.log('pwet');
}
catch (e)
{
console.error('pwet');
console.error(e);
}
context.state.commands[context.options.name] = context.options.path;
return context.state.commit();
Expand Down
48 changes: 22 additions & 26 deletions packages/commands/src/net-socket-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,59 @@ import { Socket } from 'net';
import { TLSSocket, connect as tlsconnect } from 'tls'
import * as jsonrpcws from '@akala/json-rpc-ws';
import { EventEmitter } from 'events';
import { addHandler } from './protocol-handler.js';
import { JsonRpc } from './processors/jsonrpc.js';
import { handlers } from './protocol-handler.js';
import { JsonRpc, handler } from './processors/jsonrpc.js';
import { Command } from './metadata/command.js';

addHandler('tcp', async (url) =>
handlers.useProtocol('tcp', async (url, handler) =>
{
const socket = new Socket();
await new Promise<void>(resolve => socket.connect({ port: url.port && Number(url.port) || 31416, host: url.hostname }, resolve));

const connection = JsonRpc.getConnection(new NetSocketAdapter(socket));

return {
processor: new JsonRpc(connection, true), getMetadata: () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', { param: true }, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata.commands) : reject(err)
))
};
handler.processor = new JsonRpc(connection, true);
handler.getMetadata = () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', { param: true }, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata.commands) : reject(err)
))
});

addHandler('tcps', async (url) =>
handlers.useProtocol('tcps', async (url, handler) =>
{
const socket = await new Promise<TLSSocket>(resolve => { const socket = tlsconnect({ port: url.port && Number(url.port) || 31416, host: url.hostname, servername: url.hostname }, () => resolve(socket)) });

const connection = JsonRpc.getConnection(new NetSocketAdapter(socket));

return {
processor: new JsonRpc(connection, true), getMetadata: () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', { param: true }, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
};
handler.processor = new JsonRpc(connection, true);
handler.getMetadata = () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', { param: true }, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
});

addHandler('unix', async (url) =>
handlers.useProtocol('unix', async (url, handler) =>
{
const socket = new Socket();
await new Promise<void>(resolve => socket.connect({ path: url.hostname + url.pathname }, resolve));

const connection = JsonRpc.getConnection(new NetSocketAdapter(socket));

return {
processor: new JsonRpc(connection, true), getMetadata: () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', undefined, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
};
handler.processor = new JsonRpc(connection, true);
handler.getMetadata = () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', undefined, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
});


addHandler('unixs', async (url) =>
handlers.useProtocol('unixs', async (url, handler) =>
{
const socket = await new Promise<TLSSocket>(resolve => { const socket = tlsconnect({ path: url.hostname + url.pathname }, () => resolve(socket)) });

const connection = JsonRpc.getConnection(new NetSocketAdapter(socket));

return {
processor: new JsonRpc(connection, true), getMetadata: () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', undefined, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
};
handler.processor = new JsonRpc(connection, true);
handler.getMetadata = () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', undefined, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
});

export class NetSocketAdapter implements jsonrpcws.SocketAdapter
Expand Down
4 changes: 2 additions & 2 deletions packages/commands/src/processors/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { StructuredParameters, ICommandProcessor, CommandMetadataProcessorSignat
import { MiddlewarePromise, EventEmitter } from "@akala/core";
import { Command } from '../metadata/index.js';
import { Container } from '../model/container.js';
import { addHandler } from '../protocol-handler.js';
import { handlers } from '../protocol-handler.js';

addHandler('event', async (_url, inner) => ({ processor: new EventProcessor(inner.processor), getMetadata: inner.getMetadata }));
handlers.useProtocol('event', async (_url, inner) => ({ processor: new EventProcessor(inner.processor), getMetadata: inner.getMetadata }));

export class EventProcessor extends EventEmitter<{
processing: CommandMetadataProcessorSignature<unknown>,
Expand Down
11 changes: 6 additions & 5 deletions packages/commands/src/processors/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import { ExtendedConfigurations, jsonObject } from '../metadata/index.js';
import { MiddlewarePromise } from '@akala/core';
import { eachAsync } from '@akala/core';
import { createRequire } from 'module';
import { addHandler, parseQueryString } from '../protocol-handler.js';
import { HandlerResult, handlers, parseQueryString } from '../protocol-handler.js';
import { stat } from 'fs/promises';
import os from 'node:os'
import { fileURLToPath, pathToFileURL } from 'url';

async function protocolHandler(url: URL)
async function protocolHandler(url: URL, handler: HandlerResult<FileSystem>)
{
let options: DiscoveryOptions = parseQueryString(url);
if (url.searchParams.has('ignoreFileWithNoDefaultExport'))
Expand All @@ -40,11 +40,12 @@ async function protocolHandler(url: URL)
else
options.relativeTo = p;

return { processor: new FileSystem(options.relativeTo), getMetadata: () => FileSystem.discoverMetaCommands(p, options) }
handler.processor = new FileSystem(options.relativeTo);
handler.getMetadata = () => FileSystem.discoverMetaCommands(p, options);
}

addHandler('fs', protocolHandler);
addHandler('file', protocolHandler);
handlers.useProtocol('fs', protocolHandler);
handlers.useProtocol('file', protocolHandler);


export interface FileSystemConfiguration extends Metadata.Configuration
Expand Down
23 changes: 12 additions & 11 deletions packages/commands/src/processors/http-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,27 @@ import * as pathRegexp from 'path-to-regexp';
import { CommandProcessor } from '../model/processor.js';
import { Command, Configuration } from '../metadata/index.js';
import { Container } from '../model/container.js';
import { HandlerResult, addHandler } from '../protocol-handler.js';
import { HandlerResult, handlers } from '../protocol-handler.js';
import { handler } from './jsonrpc.js';

export class HttpClient extends CommandProcessor
{

public static handler(protocol: 'http' | 'https'): (url: URL) => Promise<HandlerResult<HttpClient>>
public static handler(protocol: 'http' | 'https'): (url: URL, handler: HandlerResult<HttpClient>) => Promise<void>
{
const injector = new Injector();
return function (url)
return async function (url, handler)
{
url = new URL(url);
url.protocol = protocol;
const resolveUrl = (s: string) => new URL(s, url).toString();
injector.register('$resolveUrl', resolveUrl);
return Promise.resolve({
processor: new HttpClient(injector), getMetadata()
{
return injector.injectWithName(['$http'], async (http: Http) => (await http.call(HttpClient.buildCall({ method: 'GET', route: '$metadata' }, resolveUrl))).json())(this)
}
})
handler.
processor = new HttpClient(injector);
handler.getMetadata = function ()
{
return injector.injectWithName(['$http'], async (http: Http) => (await http.call(HttpClient.buildCall({ method: 'GET', route: '$metadata' }, resolveUrl))).json())(this)
}
}
}

Expand Down Expand Up @@ -139,8 +140,8 @@ export class HttpClient extends CommandProcessor
}
}

addHandler('http', HttpClient.handler('http'));
addHandler('https', HttpClient.handler('https'));
handlers.useProtocol('http', HttpClient.handler('http'));
handlers.useProtocol('https', HttpClient.handler('https'));

export interface HttpConfiguration extends Configuration
{
Expand Down
17 changes: 8 additions & 9 deletions packages/commands/src/processors/jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { Container } from '../model/container.js';
import { Local } from './local.js';
import { Readable } from 'stream';
import { lazy, Logger, MiddlewarePromise, noop, OptionsResponse, SpecialNextParam, SerializableObject, TypedSerializableObject } from '@akala/core';
import { HandlerResult, addHandler } from '../protocol-handler.js';
import { HandlerResult, handlers } from '../protocol-handler.js';

type OnlyArray<T> = Extract<T, unknown[]>;

export async function handler(url): Promise<HandlerResult<JsonRpc>>
export async function handler(url: URL, handler: HandlerResult<JsonRpc>): Promise<void>
{
const socket = await new Promise<jsonrpcws.SocketAdapter>((resolve) =>
{
Expand All @@ -21,15 +21,14 @@ export async function handler(url): Promise<HandlerResult<JsonRpc>>
});
const connection = JsonRpc.getConnection(socket);

return {
processor: new JsonRpc(connection, true), getMetadata: () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', { param: true }, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
};
handler.processor = new JsonRpc(connection, true);
handler.getMetadata = () => new Promise<Command[]>((resolve, reject) => connection.sendMethod<any, any>('$metadata', { param: true }, (err, metadata) =>
typeof (err) == 'undefined' ? resolve(metadata) : reject(err)
))
}

addHandler('ws', handler);
addHandler('wss', handler);
handlers.useProtocol('ws', handler);
handlers.useProtocol('wss', handler);

export class JsonRpc extends CommandProcessor
{
Expand Down
7 changes: 4 additions & 3 deletions packages/commands/src/processors/log.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommandMetadataProcessorSignature, ICommandProcessor } from '../model/processor.js';
import { addHandler } from '../protocol-handler.js';
import { handlers } from '../protocol-handler.js';
import { EventProcessor } from './event.js';

export class LogProcessor extends EventProcessor
Expand All @@ -18,7 +18,8 @@ export class LogProcessor extends EventProcessor
}
}

addHandler('log', (_url, inner) =>
handlers.useProtocol('log', async (_url, handler) =>
{
return Promise.resolve({ processor: new LogProcessor(inner.processor, (...args) => console.log(args), (...args) => console.log(args)), getMetadata: inner.getMetadata });
const inner = { ...handler };
handler.processor = new LogProcessor(inner.processor, (...args) => console.log(args), (...args) => console.log(args));
})
56 changes: 20 additions & 36 deletions packages/commands/src/protocol-handler.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,29 @@
import { ErrorWithStatus, eachAsync } from "@akala/core";
import { ErrorWithStatus, UrlHandler, eachAsync } from "@akala/core";
import { CommandProcessor, ICommandProcessor, Metadata } from "./index.browser.js";

export default function getHandler(protocol: string, url: URL)
{
const processors = getHandlers(protocol.substring(0, protocol.length - 1));
return processors.reduce((previous, current) =>
{
return previous.then(p => current(url, p))
}, Promise.resolve<ReturnType<handler<ICommandProcessor>>>(null))
}
// export default function getHandler(protocol: string, url: URL)
// {
// const processors = getHandlers(protocol.substring(0, protocol.length - 1));
// return processors.reduce((previous, current) =>
// {
// return previous.then(p => current(url, p))
// }, Promise.resolve<ReturnType<handler<ICommandProcessor>>>(null))
// }

export function getHandlers(protocol: string)
{
const protocols = protocol.split('+');
const result = protocols.map(v => handlers[v]);
let x: number;
if ((x = result.findIndex(x => x === undefined)) !== -1)
throw new ErrorWithStatus(404, `No handler could be found for the protocol ${protocols[x]}`)
return result;
}
// export function getHandlers(protocol: string)
// {
// const protocols = protocol.split('+');
// const result = protocols.map(v => handlers[v]);
// let x: number;
// if ((x = result.findIndex(x => x === undefined)) !== -1)
// throw new ErrorWithStatus(404, `No handler could be found for the protocol ${protocols[x]}`)
// return result;
// }

export type HandlerResult<T> = { processor: T, getMetadata(): Promise<Metadata.Command[]> };
export type handler<T> = (arg1: URL, arg2: HandlerResult<ICommandProcessor>) => Promise<HandlerResult<T>>

const handlers: Record<string, handler<ICommandProcessor>> = {}
export type handler<T> = (arg1: URL, arg2: HandlerResult<T>) => Promise<void>

export function addHandler<T extends ICommandProcessor>(protocol: string, handler: handler<T>)
{
if (!handlers[protocol])
handlers[protocol] = handler;
else
throw new ErrorWithStatus(409, 'Another handler is already registered for the protocol ' + protocol)
}

export function removeHandler(protocol: string)
{
if (handlers[protocol])
delete handlers[protocol]
else
throw new ErrorWithStatus(404, 'There is no handler registered for the protocol ' + protocol)
}
export const handlers = new UrlHandler<[URL, HandlerResult<ICommandProcessor>]>();

export function parseQueryString(url: URL)
{
Expand Down

0 comments on commit 341872b

Please sign in to comment.