aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHolden Rohrer <hr@hrhr.dev>2020-01-29 23:49:17 -0500
committerHolden Rohrer <hr@hrhr.dev>2020-01-29 23:49:17 -0500
commit0e2883105e948ff6f35f954f8184fdd232d17a97 (patch)
tree7764d8b8aa770ddb836cb8a2dc7c580441437969
parentdf56e8a4c6b05e9f2f5c98c14af3f95a7bc6926c (diff)
parent1cc310e20dda4a378aac76b49288e6c8e2361e5e (diff)
Merge branch 'socket'
Made the socket object used by jarvis a singleton MetaSocket object to maintain clean, modular code standards. This also means that future feature addition will be easier because all references are to one object, of which the behavior can be easily changed since most systems rely on EventEmitter or callback-style structures
-rw-r--r--examples/jarvis.js72
-rw-r--r--tools/claim.js4
-rw-r--r--tools/search.js23
-rw-r--r--utils/ident.js20
-rw-r--r--utils/writewrap.js13
5 files changed, 77 insertions, 55 deletions
diff --git a/examples/jarvis.js b/examples/jarvis.js
index ca58f8b..7b5c64e 100644
--- a/examples/jarvis.js
+++ b/examples/jarvis.js
@@ -1,5 +1,9 @@
// A bot which responds to `jarvis` with a box
+// BUG: The Scheduler, Search, Claims, ident, AND Write Listener can ALL be
+// used as extensions for Socket. This would make the code so much easier to
+// understand
+
const Space = require('../space');
const Socket = require('../socket');
const ms = require('../utils/measurespace');
@@ -14,38 +18,44 @@ const wwrap = require('../utils/writewrap');
const Claims = require('../tools/claim');
//// The queue of all writes to be sent to the server @ 200chars/1000ms
-var writes = new sched.Queue(1000, 200, (elems) => main.write(elems));
-var main = new Socket();
-var claims = new Claims(detectPrompt);
+class MetaSocket extends Socket{
+ constructor(world='', delayms=1000){
+ super(world);
+ let self = this;
+ sched.Queue.call(self, 1000, 200, (elems) => self.write(elems));
+ Claims.call(self);
+ id.call(self);
+ wwrap.call(self);
+ self.sender;
+ self.on('init',(send)=>{
+ self.sender = send;
+ });
+ Search.call(this);
+ }
+}
+var main = new MetaSocket();
// See ident.js for further documentation, but this basically sets up init functions
-id(main, initOnce, init, deinit);
-writeListen = new wwrap(main);
-
-var sender;
-function init(send){
- sender = send; // tileUpdates require knowledge of the sender
- setTimeout(()=>{writes.enable()},1000); // Would fail if a write were added because it would be within a second of cursor send
- writes.enqueue(genNotif().towrite());
-}
-function deinit(){
- writes.disable();
-}
+main.on('init', (send)=>{
+ setTimeout(()=>{main.enable()},1000);
+ main.enqueue(genNotif().towrite());
+});
+main.on('close', ()=>main.disable());
-function initOnce(){
+main.on('initOnce', ()=>{
timect();
main.on('tileUpdate', tileHandler); // Should only be active after the "control space" of the notification has been established
-}
+});
//// Management utilities
// When a tile changes, processes data into usable form and runs every function in `funcs` w/ that data.
// Note that functions can edit inputs
function tileHandler(send, source, tiles){
- if (send == sender) return;
+ if (send == main.sender) return;
let tiledata = maketiles(tiles);
- claims.handle(send, tiledata.tilespaces, tiledata.locs);
+ main.handle(send, tiledata.tilespaces, tiledata.locs);
}
//// "userspace" functions for responses, like to tileUpdates
@@ -77,14 +87,14 @@ function notifRefresh(){
let diff = newnotif.copy();
if (typeof notif !== 'undefined') diff.comb(notif, comb.sub);
notif = newnotif;
- if (notifClaim) claims.unclaim(notifClaim);
- notifClaim = claims.claim(newnotif, protectArea);
+ if (notifClaim) main.unclaim(notifClaim);
+ notifClaim = main.claim(newnotif, protectArea);
return (diff.towrite());
}
function timect(){
minsUp++;
- writes.enqueue(notifRefresh());
+ main.enqueue(notifRefresh());
setTimeout(timect, 60*1000);
}
@@ -98,27 +108,25 @@ function protectArea(send, tiles, locs, id, space, ctrl){
diff.comb(tile, comb.sub);
writelist.push(...diff.towrite())
}
- writes.enqueue(writelist);
+ main.enqueue(writelist);
}
var search = new Space();
search.adhoc('jarvis'); // The search space is the word jarvis, so whenever that's caught, a relevant function can be called.
-var read = new Search(search);
+var read = new Search();
+read.match(search, respond);
var expire = {};
-function detectPrompt(send, tiles, locs){ // tries to detect the prompt ('jarvis') and calls respond if found.
- for (let i=0; i<locs.length; i++){
- let loc = locs[i];
+main.on('fallback', (send, tiles, locs) => { // tries to detect the prompt ('jarvis') and calls respond if found.
+ for (let loc of locs){
if (read.has(loc)){
clearTimeout(expire[loc]);
- delete expire[loc];
read.del(loc);
}
- let results = read.add(loc, tiles[loc]);
- if (results.length > 0) respond(results, send);
+ read.add(loc, tiles[loc]);
expire[loc] = setTimeout(() => {read.del(loc); delete expire[loc];}, 30000);
}
-}
+});
let response = new Space();
response.adhoc('yes, my liege');
@@ -129,7 +137,7 @@ function respond(coord, send){
console.log('called at', coord);
callct += 1;
response.loc = coord;
- writes.enqueue(response.towrite().concat(notifRefresh()));
+ main.enqueue(response.towrite().concat(notifRefresh()));
read.update(response);
setTimeout(() => {limits.splice(limits.indexOf(send))}, 5*1000);
limits.push(send);
diff --git a/tools/claim.js b/tools/claim.js
index 721c5ad..b43417b 100644
--- a/tools/claim.js
+++ b/tools/claim.js
@@ -5,7 +5,7 @@ const ri = require('../utils/rectintersect');
const vec = require('../utils/vec');
const comb = require('../utils/comb');
-module.exports = function(catchall){
+module.exports = function(){
// catchall is called if tileUpdate occurs w/ no relevant claim on a part.
let claims = {};
let claimId = 0;
@@ -44,6 +44,6 @@ module.exports = function(catchall){
}
claim.call(send, diffspace, rellocs, id, claim.space, claim.area); // claim.space should not be modified by the function. it is only present to make functions easier to write
}
- catchall(send, tilespaces, locs);
+ this.emit('fallback', send, tilespaces, locs);
}
}
diff --git a/tools/search.js b/tools/search.js
index 7f681f0..78e0ee7 100644
--- a/tools/search.js
+++ b/tools/search.js
@@ -12,11 +12,13 @@ function getComp(index){
return (element,needle) => (element[index] - needle[index] || element[1-index] - needle[1-index])
}
-function Search(searchBlock){ // searchBlock should be a Space object.
+function Search(){ // searchBlock should be a Space object.
this.tiles = {}; // Object which stores Spaces.
this.sort = [[],[]]; // Vertically/horizontally sorted list of tiles for fast addition, deletion, and searching
+ this.spaces = [];
+ this.calls = [];
- this.add = function(loc, space){ // loc should be [tileY,tileX] and space Space.
+ this.add = function(loc, space, send){ // loc should be [tileY,tileX] and space Space.
this.tiles[loc] = space;
let inds = Array(2); // Records horizontal and vertical indices for insertion. Then actually inserts the item.
[0,1].forEach( ind => { // ind chooses y-or-x
@@ -29,8 +31,10 @@ function Search(searchBlock){ // searchBlock should be a Space object.
block.forEach( (tile) => {
searchspace.comb( this.tiles[tile], comb.add );
});
- coords = searchspace.search(searchBlock); // According to space docs, [] on failure and a character location on success
- return vec.add(coords, searchspace.loc);
+ for (let i=0; i<this.spaces.length; i++){
+ let coords = searchspace.search(this.spaces[i]);
+ if (coords.length) this.calls[i](vec.add(coords, searchspace.loc), send, searchspace);
+ }
}
this.block = function(loc,inds,exclude){
@@ -79,6 +83,17 @@ function Search(searchBlock){ // searchBlock should be a Space object.
else this.add(tile, tiles[tile]);
}
}
+
+ this.match = function(space, call){
+ this.spaces.push(space);
+ this.calls.push(call);
+ }
+
+ this.unmatch = function(space){
+ let ind = this.spaces.indexOf(space);
+ this.spaces.splice(ind, 1);
+ this.calls.splice(ind, 1);
+ }
}
module.exports = Search;
diff --git a/utils/ident.js b/utils/ident.js
index 187132f..b4fa8ff 100644
--- a/utils/ident.js
+++ b/utils/ident.js
@@ -2,32 +2,32 @@
const vec = require('../utils/vec');
-module.exports = function identify(sock, initOnce, init, deinit){
- // `sock` should be Socket instance.
+module.exports = function identify(){
+ // `this` should be Socket instance.
// initOnce and init should be functions that act like they describe; initOnce runs once per program execution and init whenever the socket turns back on
- sock.on('open', ()=>{
+ let self = this;
+
+ self.on('open', ()=>{
// "Pings" the server with a cursor location which is detected and saved by identity()
let coords = [Math.floor(Math.random()*100000+16), Math.floor(Math.random()*1000000+16)];
- sock.cursor(coords);
- sock.on('cursor', detect);
+ self.cursor(coords);
+ self.on('cursor', detect);
function detect(pos, send){
if (vec.equals(pos[0],coords)){
- sock.off('cursor', detect);
+ self.off('cursor', detect);
identity(send);
}
}
});
- sock.on('close', deinit);
-
// Calls initOnce and init on successful identification.
let initialized = false;
function identity(send){
if (! initialized){
initialized = true;
- initOnce();
+ self.emit('initOnce');
}
- init(send);
+ self.emit('init', send);
}
}
diff --git a/utils/writewrap.js b/utils/writewrap.js
index 3ca7ede..2e2ae07 100644
--- a/utils/writewrap.js
+++ b/utils/writewrap.js
@@ -1,12 +1,11 @@
// An EventEmitter wrapper for socket.js writes
const EventEmitter = require('events');
-class wwrap extends EventEmitter{
- constructor(socket){
- super();
- socket.on('write', (acc) => { // Assumed that none are rejected because I've never seen it
- for (let w of acc) this.emit(w);
- });
- }
+function wwrap(){ // should be called with wwrap.call(socket)
+ let self = this;
+ self.on('write', (acc) => {
+ for (let w of acc) this.emit(w);
+ });
}
+
module.exports = wwrap;