Skip to content

Instantly share code, notes, and snippets.

@TrevorBasinger
Created September 1, 2014 00:41
Show Gist options
  • Save TrevorBasinger/889df1575cbb1dff3bc1 to your computer and use it in GitHub Desktop.
Save TrevorBasinger/889df1575cbb1dff3bc1 to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
var Future = require('data.future');
var Either = require('data.either');
var State = require('fantasy-states');
var Tuple2 = require('fantasy-tuples').Tuple2;
var Tuple3 = require('fantasy-tuples').Tuple3;
var IO = require('fantasy-io');
var Maybe = require('pointfree-fantasy/instances/maybe');
var _ = require('ramda');
var http = require('http');
var rl = require('readline');
var daggy = require('daggy');
var OLens = require('fantasy-lenses').Lens.objectLens;
var io = require('socket.io-client');
require('pointfree-fantasy').expose(global);
/////////////////////////////////////////////////////////////////
//// Application
//// This application runs in a loop. As notifications are posted
//// to the Autobeacon db, this bot will manage dispatching
//// notifications.
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
//// Pure Code
/////////////////////////////////////////////////////////////////
/* Lens Helpers */
var get = function (lens) { return lens.get(); };
var set = curry (function (obj, lens) { return lens.set (obj); });
/////////////////////////////////////////////////////////////////
// Bot Pointed Functor
/////////////////////////////////////////////////////////////////
Bot = daggy.tagged ('config');
Bot.of = function (c) { return Bot (c); };
Bot.prototype.map = function (f) { return f (this.config); };
/////////////////////////////////////////////////////////////////
// Bot Lenses
// idLens :: BotConfig -> Lens
var idLens = OLens ('id').run;
// roleLens :: BotConfig -> Lens
var roleLens = OLens ('role').run;
/////////////////////////////////////////////////////////////////
// Bot Lens Accessors
// setId :: id -> Bot -> Bot
var setId = curry (function (id) { return compose (Bot.of, set (id), map (idLens)); });
// getId :: Bot -> Int
var getId = compose (get, map(idLens));
// setRole :: role -> Bot -> Bot
var setRole = function (role) { return compose (Bot.of, set (role), map (roleLens)); };
// getRole :: Bot -> Int
var getRole = compose (get, map (roleLens));
// determineRole :: String -> String -> String
var determineRole = function (suggested, conflict) {
if (suggested === '') { return determineRole ('manager', conflict) }
if (suggested === 'manager') { if (conflict === 'manager') {
return determineRole ('queue', null); } }
if (suggested === 'queue') { if (conflict === 'queue') {
return determineRole ('client', null); } }
if (suggested === 'client') { return 'client'; }
return suggested;
}
// resolveConflicts :: Config -> Bot -> Bot
var resolveConflicts = curry (function (config, bot) {
if(config.id === getId (bot)) return bot;
var n = determineRole (getRole (bot), config.role);
return setRole (n) (bot);
});
// main :: ConfigObj -> Socket.IO.Socket -> IO ()
var main = function (config, s) {
var bot = Bot.of (config);
return IO.of (s)
.chain (function (socket) {
socket.on ('status', function (d) { bot = resolveConflicts (d, bot); });
socket.on ('all', function (d) {
if (d.fromId !== getId (bot)) {
if (d.action === 'statusCheck') { socket.emit ('status', map (I, bot)); }}});
socket.emit ('all', { action: 'statusCheck', fromId: getId (bot) });
return IO.of ()
});
}
/////////////////////////////////////////////////////////////////
//// Impure Code
/////////////////////////////////////////////////////////////////
function randomInt (min, max) {
return Math.floor (Math.random() * (max - min + 1)) + min;
}
var config = {
id: randomInt(0, 999999),
role: 'manager',
status: ''
};
main (config, io.connect ('http://localhost:1234')).unsafePerform();
@TrevorBasinger
Copy link
Author

I think I may be "doing it wrong" in the main function. I'm not sure how to allow my socket handler make changes to bot and have that state kept after the handler exits.

@TrevorBasinger
Copy link
Author

I've also looked at Baconjs. I'm not sure how I would apply it in a way that would give me more value that what just socket.io has. I'm interested to hear how you might apply it.

@DrBoolean
Copy link

Sorry of the delay on this. I think the Reader or State monad can be used in place of Bot. Then we can use local or modify to update and maintain internal state.

Bacon will help us model sockets in a pure way. For instance, we can get tangible streams of status and all events which can be mapped over. This eliminates the need for IO.

What does the server look like? (localhost:1234). I wanted to try to play with it, but i'm struggling to dig deep without seeing it work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment