starting event matching

beta
Theunis Botha 2020-04-23 15:26:54 +02:00
parent bbb4296c11
commit ca7bf07b21
19 changed files with 4144 additions and 7 deletions

View File

@ -1,5 +1,6 @@
const R3 = require('./r3.js');
R3.System.Linking.start();
R3.System.Socket.start();
module.exports = R3;

170
dist/r3-node/r3-event.js vendored Normal file
View File

@ -0,0 +1,170 @@
const Utils = require('r3-utils.js');
class Event {
constructor() {
console.log('Event created');
}
/**
* Some nice Events handling
* @type {{}}
*/
static Subscriptions = {};
static Subscribe(
eventName,
fn
) {
/**
* Todo - maybe eventually store a boolean which indicates if the function has been executed
*/
let subscriptionId = Utils.RandomId(10);
if (Event.Subscriptions.hasOwnProperty(eventName)) {
if (Event.Subscriptions[eventName][subscriptionId]) {
throw new Error('A component can only subscribe to a particular event ID once');
}
Event.Subscriptions[eventName][subscriptionId] = fn;
} else {
Event.Subscriptions[eventName] = {};
Event.Subscriptions[eventName][subscriptionId] = fn;
}
/**
* Return a handle to the caller to allow us to unsubscribe to this event
*/
return {
fn: fn,
remove: function (eventId, subscriptionId) {
return function () {
/**
* Stop listening for this event from this component
*/
delete Event.Subscriptions[eventId][subscriptionId];
/**
* If the length of listeners is 0, stop referencing this event
* @type {string[]}
*/
let listeners = Object.keys(Event.Subscriptions[eventId]);
if (listeners.length === 0) {
delete Event.Subscriptions[eventId];
}
}
}(eventName, subscriptionId),
subscriptionId : subscriptionId
};
};
/**
* Subscribe to some events
* @param eventName
* @param callback
*/
subscribe(
eventName,
callback
) {
return Event.Subscribe(eventName, callback.bind(this));
};
/**
* Static Synchronous Event - Calls clientCallback directly after the event result is obtained
* @param eventId
* @param data
* @param clientCallback is executed ideally when the event completed
* @param clientErrorCallback
* @returns {number} of callbacks executed
* @constructor
*/
static Emit(
eventId,
data,
clientCallback,
clientErrorCallback
) {
if (Event.Subscriptions.hasOwnProperty(eventId)) {
let subscriptionIds = Object.keys(Event.Subscriptions[eventId]);
subscriptionIds.map(
function(subscriptionId) {
try {
let result = Event.Subscriptions[eventId][subscriptionId](data);
if (clientCallback) {
clientCallback(result);
}
} catch (error) {
if (clientErrorCallback) {
clientErrorCallback(error);
} else {
console.error(error);
throw error;
}
}
}
)
}
}
emit(
eventName,
data,
clientCallback,
clientErrorCallback
) {
return Event.Emit(
eventName,
data,
clientCallback,
clientErrorCallback
);
}
/**
* Execute the functions which subscribe to this event, but don't process the client callback - the subscription function
* should execute the client callback
* @param eventId
* @param data
* @param clientCallback
* @param clientErrorCallback
* @returns {number}
* @constructor
*/
static Async(
eventId,
data,
clientCallback,
clientErrorCallback
) {
if (Event.Subscriptions.hasOwnProperty(eventId)) {
let subscriptionIds = Object.keys(Event.Subscriptions[eventId]);
subscriptionIds.map(
function(subscriptionId) {
try {
Event.Subscriptions[eventId][subscriptionId](data, clientCallback, clientErrorCallback);
} catch (error) {
if (clientErrorCallback) {
clientErrorCallback(error);
} else {
console.error(error);
throw error;
}
}
}
)
}
};
}
module.exports = Event;

24
dist/r3-node/r3-system-socket.js vendored Normal file
View File

@ -0,0 +1,24 @@
const System = require('./r3-system.js');
module.exports = class SocketSystem extends System {
constructor() {
super();
console.log('hi there from socket system');
}
static start() {
super.start();
console.log('starting socket system');
return true;
}
}

1245
dist/r3-node/r3-utils.js vendored Normal file

File diff suppressed because it is too large Load Diff

4
dist/r3-node/r3.js vendored
View File

@ -1,5 +1,6 @@
const System = require('./r3-system.js');
const SystemLinking = require('./r3-system-linking.js');
const SystemSocket = require('./r3-system-socket.js');
const Object = require('./r3-object.js');
class R3 {
@ -9,7 +10,7 @@ class R3 {
}
static version() {
return 'Tue Apr 21 2020 11:52:51 GMT+0200 (Central European Summer Time)';
return 'Thu Apr 23 2020 14:42:47 GMT+0200 (Central European Summer Time)';
}
}
@ -17,5 +18,6 @@ class R3 {
R3.Object = Object;
R3.System = System;
R3.System.Linking = SystemLinking;
R3.System.Socket = SystemSocket;
module.exports = R3;

42
dist/r3.js vendored

File diff suppressed because one or more lines are too long

66
src/api/index.js Normal file
View File

@ -0,0 +1,66 @@
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const socketio = require('@feathersjs/socketio');
// A messages service that allows to create new
// and return all existing messages
class MessageService {
constructor() {
this.messages = [];
}
async find () {
// Just return all our messages
return this.messages;
}
async create (data) {
// The new message is the data merged with a unique identifier
// using the messages length since it changes whenever we add one
const message = {
id: this.messages.length,
text: data.text
};
// Add new message to the list
this.messages.push(message);
return message;
}
}
// Creates an ExpressJS compatible Feathers application
const app = express(feathers());
// Parse HTTP JSON bodies
app.use(express.json());
// Parse URL-encoded params
app.use(express.urlencoded({ extended: true }));
// Host static files from the current folder
app.use(express.static(__dirname + '/../portal'));
// Add REST API support
app.configure(express.rest());
// Configure Socket.io real-time APIs
app.configure(socketio());
// Register an in-memory messages service
app.use('/messages', new MessageService());
// Register a nicer error handler than the default Express one
app.use(express.errorHandler());
// Add any new real-time connection to the `everybody` channel
app.on('connection', connection =>
app.channel('everybody').join(connection)
);
// Publish all events to the `everybody` channel
app.publish(data => app.channel('everybody'));
// Start the server
app.listen(3030).on('listening', () =>
console.log('Feathers server listening on localhost:3030')
);
// For good measure let's create a message
// So our API doesn't look so empty
app.service('messages').create({
text: 'Hello world from the server'
});

View File

@ -3,12 +3,15 @@ const clean = require('gulp-clean');
const stringReplace = require('gulp-string-replace');
const webpack_stream = require('webpack-stream');
const webpack_config = require('./webpack.config.js');
const map = require('map-stream');
gulp.task('build', gulp.series([clearBuild, gulp.parallel(build, buildNode)]));
gulp.task('default', gulp.series([clearBuild, gulp.parallel(build, buildNode), monitor]));
gulp.task('buildEvents', buildEvents);
const paths = {
source : './src/r3/*.js',
testSource : './test/*.js',
web : './dist',
node : './dist/r3-node'
};
@ -35,6 +38,130 @@ function buildNode() {
.pipe(gulp.dest(paths.node));
}
function logMatches(regex) {
return map(function(file, done) {
//console.log(file);
let contents = file.contents.toString();
let m;
do {
m = regex.exec(contents);
if (m) {
console.log(m[0]);
}
} while (m);
// let matches = [...contents.matchAll(regex)];
// if (matches) {
// matches.map(
// function(match) {
// console.log(match[0]);
// }
// )
// }
// file.contents.toString().match(regex).forEach(function(match) {
// console.log(file.path + ': ' + match);
// });
done(null, file);
});
}
function buildEvents() {
return gulp.src(
[
paths.source,
paths.testSource
]
).pipe(logMatches(/Event\.([A-Z]+_*){2,}/g));
// $files = scandir('.', SCANDIR_SORT_DESCENDING);
//
// $events = [];
//
// foreach ($files as $file) {
//
//
// if (
// preg_match('/\.js$/', $file) &&
// !preg_match('/r3\-a\-2\-event/', $file)
// ) {
// echo "processing file " . $file . "\n";
//
// $fn = fopen($file, "r");
//
// while (!feof($fn)) {
// $line = fgets($fn);
//
//
// if (
// preg_match('/R3.Event\./', $line) &&
// !preg_match('/Emit|Subscribe|.call|GetEventName|Async|prototype/', $line)
// ) {
// $matches = [];
// preg_match_all('/(R3.Event\..*?)(\s+|,|;|$|\))/', $line, $matches);
//
// if ($matches[1] && $matches[1][0]) {
//
// $event = $matches[1][0];
//
// if (in_array($event, $events)) {
// // Do nothing
// } else {
// array_push($events, $event);
// }
//
// }
//
//
// }
//
//
// }
//
// fclose($fn);
// }
//
//
// }
//
// array_push($events, 'R3.Event.START');
// array_push($events, 'R3.Event.PAUSE');
// array_push($events, 'R3.Event.RESTART');
//
// sort($events);
//
// $i = 1;
//
// $eventList = '';
//
// $eventFunction = "/**\n * R3.Event.GetEventName\n * @param eventId\n * @returns {string}\n * @constructor\n */\nR3.Event.GetEventName = function(eventId) {\n\n\tswitch(eventId) {\n";
//
// foreach ($events as $event) {
// $eventList .= $event . " = " . "0x" . dechex($i) . ";\n";
//
// $eventFunction .= "\t\tcase 0x" . dechex($i). " : return '" . strtolower(str_replace('R3.Event.', '', $event)) . "';\n";
//
// $i++;
// }
//
// $eventList .= "R3.Event.MAX_EVENTS = " . "0x" . dechex($i) . ";\n\n";
//
// $eventFunction .= "\t\tdefault :\n\t\t\tthrow new Error('Event type not defined : ' + eventId);\n";
// $eventFunction .= "\t}\n\n";
// $eventFunction .= "};\n";
//
// echo $eventList;
// echo $eventFunction;
//
// file_put_contents('r3-a-2-event-1.js', $eventList . $eventFunction);
}
function monitor() {
const watcher = gulp.watch(

931
src/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,9 @@
"description": "",
"private": true,
"dependencies": {
"@feathersjs/express": "^4.5.3",
"@feathersjs/feathers": "^4.5.3",
"@feathersjs/socketio": "^4.5.3",
"chai": "^4.2.0",
"mocha": "^7.1.1",
"webpack": "^4.41.6",
@ -15,6 +18,7 @@
"gulp-concat": "^2.6.1",
"gulp-sort": "^2.0.0",
"gulp-string-replace": "^1.1.2",
"map-stream": "0.0.7",
"webpack-cli": "^3.3.11"
},
"scripts": {

62
src/portal/index.html Normal file
View File

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Feathers Example</title>
<link rel="stylesheet" href="//unpkg.com/feathers-chat@4.0.0/public/base.css">
<link rel="stylesheet" href="//unpkg.com/feathers-chat@4.0.0/public/chat.css">
</head>
<body>
<main id="main" class="container">
<h1>Welcome to Feathers</h1>
<form class="form" onsubmit="sendMessage(event.preventDefault())">
<input type="text" id="message-text" placeholder="Enter message here">
<button type="submit" class="button button-primary">Send message</button>
</form>
<h2>Here are the current messages:</h2>
</main>
<script src="//unpkg.com/@feathersjs/client@^4.3.0/dist/feathers.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script type="text/javascript">
// Set up socket.io
const socket = io('http://localhost:3030');
// Initialize a Feathers app
const app = feathers();
// Register socket.io to talk to our server
app.configure(feathers.socketio(socket));
// Form submission handler that sends a new message
async function sendMessage () {
const messageInput = document.getElementById('message-text');
// Create a new message with the input field value
await app.service('messages').create({
text: messageInput.value
});
messageInput.value = '';
}
// Renders a single message on the page
function addMessage (message) {
document.getElementById('main').innerHTML += `<p>${message.text}</p>`;
}
const main = async () => {
// Find all existing messages
const messages = await app.service('messages').find();
// Add existing messages to the list
messages.forEach(addMessage);
// Add any newly created message to the list in real-time
app.service('messages').on('created', addMessage);
};
main();
</script>
</body>
</html>

View File

@ -1,5 +1,6 @@
const R3 = require('./r3.js');
R3.System.Linking.start();
R3.System.Socket.start();
module.exports = R3;

170
src/r3/r3-event.js Normal file
View File

@ -0,0 +1,170 @@
const Utils = require('r3-utils.js');
class Event {
constructor() {
console.log('Event created');
}
/**
* Some nice Events handling
* @type {{}}
*/
static Subscriptions = {};
static Subscribe(
eventName,
fn
) {
/**
* Todo - maybe eventually store a boolean which indicates if the function has been executed
*/
let subscriptionId = Utils.RandomId(10);
if (Event.Subscriptions.hasOwnProperty(eventName)) {
if (Event.Subscriptions[eventName][subscriptionId]) {
throw new Error('A component can only subscribe to a particular event ID once');
}
Event.Subscriptions[eventName][subscriptionId] = fn;
} else {
Event.Subscriptions[eventName] = {};
Event.Subscriptions[eventName][subscriptionId] = fn;
}
/**
* Return a handle to the caller to allow us to unsubscribe to this event
*/
return {
fn: fn,
remove: function (eventId, subscriptionId) {
return function () {
/**
* Stop listening for this event from this component
*/
delete Event.Subscriptions[eventId][subscriptionId];
/**
* If the length of listeners is 0, stop referencing this event
* @type {string[]}
*/
let listeners = Object.keys(Event.Subscriptions[eventId]);
if (listeners.length === 0) {
delete Event.Subscriptions[eventId];
}
}
}(eventName, subscriptionId),
subscriptionId : subscriptionId
};
};
/**
* Subscribe to some events
* @param eventName
* @param callback
*/
subscribe(
eventName,
callback
) {
return Event.Subscribe(eventName, callback.bind(this));
};
/**
* Static Synchronous Event - Calls clientCallback directly after the event result is obtained
* @param eventId
* @param data
* @param clientCallback is executed ideally when the event completed
* @param clientErrorCallback
* @returns {number} of callbacks executed
* @constructor
*/
static Emit(
eventId,
data,
clientCallback,
clientErrorCallback
) {
if (Event.Subscriptions.hasOwnProperty(eventId)) {
let subscriptionIds = Object.keys(Event.Subscriptions[eventId]);
subscriptionIds.map(
function(subscriptionId) {
try {
let result = Event.Subscriptions[eventId][subscriptionId](data);
if (clientCallback) {
clientCallback(result);
}
} catch (error) {
if (clientErrorCallback) {
clientErrorCallback(error);
} else {
console.error(error);
throw error;
}
}
}
)
}
}
emit(
eventName,
data,
clientCallback,
clientErrorCallback
) {
return Event.Emit(
eventName,
data,
clientCallback,
clientErrorCallback
);
}
/**
* Execute the functions which subscribe to this event, but don't process the client callback - the subscription function
* should execute the client callback
* @param eventId
* @param data
* @param clientCallback
* @param clientErrorCallback
* @returns {number}
* @constructor
*/
static Async(
eventId,
data,
clientCallback,
clientErrorCallback
) {
if (Event.Subscriptions.hasOwnProperty(eventId)) {
let subscriptionIds = Object.keys(Event.Subscriptions[eventId]);
subscriptionIds.map(
function(subscriptionId) {
try {
Event.Subscriptions[eventId][subscriptionId](data, clientCallback, clientErrorCallback);
} catch (error) {
if (clientErrorCallback) {
clientErrorCallback(error);
} else {
console.error(error);
throw error;
}
}
}
)
}
};
}
module.exports = Event;

View File

@ -0,0 +1,24 @@
const System = require('./r3-system.js');
module.exports = class SocketSystem extends System {
constructor() {
super();
console.log('hi there from socket system');
}
static start() {
super.start();
console.log('starting socket system');
return true;
}
}

1245
src/r3/r3-utils.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
const System = require('./r3-system.js');
const SystemLinking = require('./r3-system-linking.js');
const SystemSocket = require('./r3-system-socket.js');
const Object = require('./r3-object.js');
class R3 {
@ -17,5 +18,6 @@ class R3 {
R3.Object = Object;
R3.System = System;
R3.System.Linking = SystemLinking;
R3.System.Socket = SystemSocket;
module.exports = R3;

25
test/Event.test.js Normal file
View File

@ -0,0 +1,25 @@
const {assert} = require('chai');
describe('Event Tests', () => {
it (
'Tests Events',
() => {
let event = new Event();
let result = event.subscribe(
R3.Event.TEST_EVENT,
() => {
}
);
console.log(result);
assert.typeOf(result, 'string');
}
);
});

View File

@ -1,8 +1,7 @@
const {expect} = require('chai');
const LinkingSystem = require('../src/r3/r3-system-linking');
const System = require('../src/r3/r3-system');
const System = require('../src/r3/r3-system');
describe('Linking System Tests', () => {

View File

@ -1,9 +1,10 @@
const {assert} = require('chai');
const Event = require('../src/r3/r3-event.js');
describe('R3 Tests', () => {
describe('Event Tests', () => {
it (
'Tests R3 is compiled and working',
'Tests Event Subscriptions',
() => {
const R3 = require('../dist/r3-node/');