2020-12-21 21:01:37 +00:00
|
|
|
|
import * as plugins from './typedsocket.plugins';
|
2021-01-23 04:22:47 +00:00
|
|
|
|
import type * as smartexpress from '@pushrocks/smartexpress';
|
2020-12-21 21:01:37 +00:00
|
|
|
|
|
2020-12-26 18:14:19 +00:00
|
|
|
|
const publicRoleName = 'publicRoleName';
|
|
|
|
|
const publicRolePass = 'publicRolePass';
|
|
|
|
|
|
2021-01-28 02:12:22 +00:00
|
|
|
|
export type TTypedSocketSide = 'server' | 'client';
|
|
|
|
|
|
2020-12-21 21:01:37 +00:00
|
|
|
|
export class TypedSocket {
|
2020-12-26 18:14:19 +00:00
|
|
|
|
// STATIC
|
|
|
|
|
/**
|
|
|
|
|
* creates a typedsocket server
|
|
|
|
|
* note: this will fail in browser environments as server libs are not bundled.
|
|
|
|
|
*/
|
|
|
|
|
public static async createServer(
|
|
|
|
|
typedrouterArg: plugins.typedrequest.TypedRouter,
|
2021-01-23 04:22:47 +00:00
|
|
|
|
smartexpressServerArg?: smartexpress.Server
|
2020-12-26 18:14:19 +00:00
|
|
|
|
): Promise<TypedSocket> {
|
|
|
|
|
const smartsocketServer = new plugins.smartsocket.Smartsocket({
|
|
|
|
|
port: 3000,
|
|
|
|
|
});
|
|
|
|
|
if (smartexpressServerArg) {
|
|
|
|
|
smartsocketServer.setExternalServer('smartexpress', smartexpressServerArg);
|
|
|
|
|
}
|
|
|
|
|
const publicRole = new plugins.smartsocket.SocketRole({
|
|
|
|
|
name: publicRoleName,
|
|
|
|
|
passwordHash: await plugins.isohash.sha256FromString(publicRolePass),
|
|
|
|
|
});
|
|
|
|
|
smartsocketServer.addSocketRoles([publicRole]);
|
|
|
|
|
smartsocketServer.socketFunctions.add(
|
|
|
|
|
new plugins.smartsocket.SocketFunction({
|
|
|
|
|
funcName: 'processMessage',
|
|
|
|
|
allowedRoles: [publicRole],
|
|
|
|
|
funcDef: async (dataArg, socketConnectionArg) => {
|
|
|
|
|
return typedrouterArg.routeAndAddResponse(dataArg);
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
const typedsocket = new TypedSocket(
|
2021-01-28 02:12:22 +00:00
|
|
|
|
'server',
|
2020-12-26 18:14:19 +00:00
|
|
|
|
typedrouterArg,
|
|
|
|
|
async <T extends plugins.typedrequestInterfaces.ITypedRequest>(
|
|
|
|
|
dataArg: T,
|
|
|
|
|
targetConnectionArg?: plugins.smartsocket.SocketConnection
|
|
|
|
|
): Promise<T> => {
|
|
|
|
|
if (!targetConnectionArg) {
|
|
|
|
|
if ((smartsocketServer.socketConnections.getArray().length = 1)) {
|
|
|
|
|
console.log(
|
|
|
|
|
'Since no targetConnection was supplied and there is only one active one present, choosing that one automatically'
|
|
|
|
|
);
|
|
|
|
|
targetConnectionArg = smartsocketServer.socketConnections.getArray()[0];
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('you need to specify the wanted targetConnection');
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-26 18:45:17 +00:00
|
|
|
|
const response: T = await smartsocketServer.clientCall(
|
2020-12-26 18:14:19 +00:00
|
|
|
|
'processMessage',
|
|
|
|
|
dataArg,
|
|
|
|
|
targetConnectionArg
|
2020-12-26 18:45:17 +00:00
|
|
|
|
) as any;
|
2020-12-26 18:14:19 +00:00
|
|
|
|
return response;
|
|
|
|
|
},
|
|
|
|
|
smartsocketServer
|
|
|
|
|
);
|
|
|
|
|
await smartsocketServer.start();
|
|
|
|
|
|
|
|
|
|
return typedsocket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async createClient(
|
|
|
|
|
typedrouterArg: plugins.typedrequest.TypedRouter,
|
2021-01-21 14:26:48 +00:00
|
|
|
|
serverUrlArg: string,
|
|
|
|
|
aliasArg = 'clientArg'
|
2020-12-26 18:14:19 +00:00
|
|
|
|
): Promise<TypedSocket> {
|
2021-01-22 15:13:05 +00:00
|
|
|
|
const domain = new plugins.smartstring.Domain(serverUrlArg);
|
|
|
|
|
|
2021-01-23 05:14:29 +00:00
|
|
|
|
const socketOptions = {
|
2021-01-21 14:26:48 +00:00
|
|
|
|
alias: aliasArg,
|
2020-12-26 18:14:19 +00:00
|
|
|
|
role: publicRoleName,
|
|
|
|
|
password: publicRolePass,
|
2021-01-22 15:13:05 +00:00
|
|
|
|
port: domain.port || 3000,
|
2021-01-23 05:14:29 +00:00
|
|
|
|
url: `${domain.nodeParsedUrl.protocol}//${domain.nodeParsedUrl.hostname}`,
|
2020-12-26 18:14:19 +00:00
|
|
|
|
autoReconnect: true,
|
2021-01-23 05:14:29 +00:00
|
|
|
|
}
|
2021-01-28 12:58:42 +00:00
|
|
|
|
console.log(`starting typedsocket with the following settings:`)
|
2021-01-23 05:14:29 +00:00
|
|
|
|
console.log(socketOptions);
|
|
|
|
|
const smartsocketClient = new plugins.smartsocket.SmartsocketClient(socketOptions);
|
2020-12-26 18:45:17 +00:00
|
|
|
|
smartsocketClient.addSocketFunction(
|
2020-12-26 18:14:19 +00:00
|
|
|
|
new plugins.smartsocket.SocketFunction({
|
|
|
|
|
funcName: 'processMessage',
|
|
|
|
|
allowedRoles: [],
|
|
|
|
|
funcDef: async (dataArg, socketConnectionArg) => {
|
|
|
|
|
return typedrouterArg.routeAndAddResponse(dataArg);
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
const typedsocket = new TypedSocket(
|
2021-01-28 02:12:22 +00:00
|
|
|
|
'client',
|
2020-12-26 18:14:19 +00:00
|
|
|
|
typedrouterArg,
|
|
|
|
|
async <T extends plugins.typedrequestInterfaces.ITypedRequest>(dataArg: T): Promise<T> => {
|
|
|
|
|
const response: T = (smartsocketClient.serverCall('processMessage', dataArg) as any) as T;
|
|
|
|
|
return response;
|
|
|
|
|
},
|
|
|
|
|
smartsocketClient
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await smartsocketClient.connect();
|
|
|
|
|
|
|
|
|
|
return typedsocket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// INSTANCE
|
2021-01-28 02:12:22 +00:00
|
|
|
|
public side: TTypedSocketSide;
|
2020-12-26 18:14:19 +00:00
|
|
|
|
public typedrouter: plugins.typedrequest.TypedRouter;
|
|
|
|
|
private postMethod: plugins.typedrequest.IPostMethod &
|
|
|
|
|
((
|
|
|
|
|
typedRequestPostObject: plugins.typedrequestInterfaces.ITypedRequest,
|
|
|
|
|
socketConnectionArg?: plugins.smartsocket.SocketConnection
|
|
|
|
|
) => Promise<plugins.typedrequestInterfaces.ITypedRequest>);
|
|
|
|
|
private socketServerOrClient: plugins.smartsocket.Smartsocket | plugins.smartsocket.SmartsocketClient;
|
|
|
|
|
constructor(
|
2021-01-28 02:12:22 +00:00
|
|
|
|
sideArg: TTypedSocketSide,
|
2020-12-26 18:14:19 +00:00
|
|
|
|
typedrouterArg: plugins.typedrequest.TypedRouter,
|
|
|
|
|
postMethodArg: plugins.typedrequest.IPostMethod,
|
|
|
|
|
socketServerOrClientArg: plugins.smartsocket.Smartsocket | plugins.smartsocket.SmartsocketClient
|
|
|
|
|
) {
|
2021-01-28 02:12:22 +00:00
|
|
|
|
this.side = sideArg;
|
2020-12-26 18:14:19 +00:00
|
|
|
|
this.typedrouter = typedrouterArg;
|
|
|
|
|
this.postMethod = postMethodArg;
|
|
|
|
|
this.socketServerOrClient = socketServerOrClientArg;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-28 02:12:22 +00:00
|
|
|
|
public addTag(keyArg: string, payloadArg: any) {
|
|
|
|
|
if (this.side === 'client' && this.socketServerOrClient instanceof plugins.smartsocket.SmartsocketClient) {
|
|
|
|
|
this.socketServerOrClient.socketConnection.addTag({
|
|
|
|
|
id: keyArg,
|
|
|
|
|
payload: payloadArg
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('tagging is only supported on clients');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-26 18:14:19 +00:00
|
|
|
|
public createTypedRequest<T extends plugins.typedrequestInterfaces.ITypedRequest>(
|
|
|
|
|
methodName: T['method'],
|
|
|
|
|
targetConnection?: plugins.smartsocket.SocketConnection
|
|
|
|
|
): plugins.typedrequest.TypedRequest<T> {
|
|
|
|
|
const typedrequest = new plugins.typedrequest.TypedRequest<T>(
|
|
|
|
|
new plugins.typedrequest.TypedTarget({
|
|
|
|
|
postMethod: async (requestDataArg) => {
|
|
|
|
|
const result = await this.postMethod(requestDataArg, targetConnection);
|
|
|
|
|
return result;
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
methodName
|
|
|
|
|
);
|
|
|
|
|
return typedrequest;
|
|
|
|
|
}
|
2020-12-21 21:01:37 +00:00
|
|
|
|
|
2021-10-22 19:09:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* returns all matching target connection
|
|
|
|
|
* @param asyncFindFuncArg
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2021-01-28 12:58:42 +00:00
|
|
|
|
public async findAllTargetConnections(
|
|
|
|
|
asyncFindFuncArg: (connectionArg: plugins.smartsocket.SocketConnection) => Promise<boolean>
|
2020-12-26 18:14:19 +00:00
|
|
|
|
) {
|
|
|
|
|
if (this.socketServerOrClient instanceof plugins.smartsocket.Smartsocket) {
|
2021-01-28 12:58:42 +00:00
|
|
|
|
const matchingSockets: plugins.smartsocket.SocketConnection[] = [];
|
2020-12-26 18:14:19 +00:00
|
|
|
|
for (const socketConnection of this.socketServerOrClient.socketConnections.getArray()) {
|
2021-01-28 12:58:42 +00:00
|
|
|
|
if (await asyncFindFuncArg(socketConnection)) {
|
|
|
|
|
matchingSockets.push(socketConnection);
|
2020-12-26 18:14:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-28 12:58:42 +00:00
|
|
|
|
return matchingSockets;
|
2020-12-26 18:14:19 +00:00
|
|
|
|
} else {
|
2021-01-28 02:12:22 +00:00
|
|
|
|
throw new Error('this method >>findTargetConnection<< is only available from the server');
|
2020-12-26 18:14:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-21 21:01:37 +00:00
|
|
|
|
|
2021-10-22 19:09:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* returns a single target connection by returning the first one of all matching ones
|
|
|
|
|
* @param asyncFindFuncArg
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2021-01-28 12:58:42 +00:00
|
|
|
|
public async findTargetConnection(
|
|
|
|
|
asyncFindFuncArg: (connectionArg: plugins.smartsocket.SocketConnection) => Promise<boolean>
|
|
|
|
|
) {
|
2021-10-22 19:09:42 +00:00
|
|
|
|
const allMatching = await this.findAllTargetConnections(asyncFindFuncArg);
|
2021-01-28 12:58:42 +00:00
|
|
|
|
return allMatching[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async findAllTargetConnectionsByTag(keyArg: string, payloadArg?: any) {
|
|
|
|
|
return this.findAllTargetConnections(async socketConnectionArg => {
|
2021-01-28 02:12:22 +00:00
|
|
|
|
let result: boolean;
|
2021-01-28 12:58:42 +00:00
|
|
|
|
if (!payloadArg) {
|
2021-10-22 19:09:42 +00:00
|
|
|
|
result = !!socketConnectionArg.getTagById(keyArg);
|
2021-01-28 02:12:22 +00:00
|
|
|
|
} else {
|
2021-10-22 19:09:42 +00:00
|
|
|
|
result = !!socketConnectionArg.getTagById(keyArg) === payloadArg;
|
2021-01-28 02:12:22 +00:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-28 12:58:42 +00:00
|
|
|
|
public async findTargetConnectionByTag(keyArg: string, payloadArg?: any) {
|
2021-10-22 19:09:42 +00:00
|
|
|
|
const allResults = await this.findAllTargetConnectionsByTag(keyArg, payloadArg)
|
2021-01-28 12:58:42 +00:00
|
|
|
|
return allResults[0];
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-26 18:14:19 +00:00
|
|
|
|
public async stop() {
|
|
|
|
|
await this.socketServerOrClient.stop()
|
|
|
|
|
}
|
|
|
|
|
}
|