hot reload makes development much more fun.
As I press ctrl-s
on documents in atom editor i like being able to work with the file or send it off to
servers and clients, or run native code compilation or other random linting, etc.
since atom is written in node.js, the idea is to open a var dgram = require('dgram')
datagram socket for low latency distribution
of any saved file path
offload processing during text edits.
A separate processes is best suited for anything from reading the file to networking the buffer content and any other stuff that could bog down the app while i'm typing.
time to install atom editor.
install the shell commands if you haven't (from the main menu next to file and edit), so you can do stuff like $ atom .
in your project directory
your editor config files are in the .atom
directory of your home folder.
open your init script.
$ cd ~/.atom
$ open init.coffee
# Your init script
#
# Atom will evaluate this file each time a new window is opened. It is run
# after packages are loaded/activated and after the previous editor state
# has been restored.
#
# An example hack to log to the console when each text editor is saved.
#
# atom.workspace.observeTextEditors (editor) ->
# editor.onDidSave ->
# console.log "Saved! #{editor.getPath()}"
atom.workspace.observeTextEditors (editor) ->
editor.onDidSave ->
require(__dirname + '/msgr.js')("#{editor.getPath()}")
we're passing the saved file path to a require call. it imports a function for handling the file path.
add the msgr.js script, since your editor will start calling it on-save.
$ touch ~/.atom/msgr.js
$ open ~/.atom/msgr.js
var dgram = require('dgram')
var sock = dgram.createSocket('udp4')
module.exports = path
function path(p){
var buf = Buffer(p)
sock.send(buf, 0, buf.length, 42000, '127.0.0.1')
}
keep it on localhost or 127.0.0.1
and grab a high port like 42000
or whatever.
now your editor can fire off little node buffers over udp's low maintenance, connectionless protocol
start a dgram server and handle the buffer from a separate node process! somewhere else, start your atomserver
directory
$ mkdir myprojects && cd myprojects
$ mkdir atomserver && cd atomserver
$ touch package.json
in package.json
add nanomsg
, the ip
module and osenv
deps:
{
"name":"atomserver by reqshark",
"dependencies": {
"ip":"",
"nanomsg":"",
"osenv":""
}
}
install it with at least node 4 or 5
$ cd ~/myprojects/atomserver
$ npm install
add a udp buffer handler and a nanomsg socket for simple distributed networking. the atomserver's main.js
:
var nano = require('nanomsg')
var server = require('dgram').createSocket('udp4')
var pub = nano.socket('pub', { tcpnodelay:true } )
// fill in your server's DNS address. if u prefer IP addresses, or soemthing on the local machine perhaps?
// the idea is to put the set of addresses wherever you're working on stuff
var addr1 = 'tcp://somepublicDNS.com:43000' || 'tcp://123.456.789.101.:43000'
var addr2 = 'tcp://10.0.1.67:43000'
// var addr3.. put as many as you want
// its better to use the same port across distributed addresses if possible, and we'll see why shortly
pub.connect(addr)
pub.connect(addr2) // nanomsg sockets can connect/bind to multiple endpoints
server.on('error', er); function er(err) { server.close(); throw err }
server.on('listening', heard)
function heard(){
var addr = this.address()
console.log('server listening '+ addr.address + ':' + addr.port)
}
server.on('message', handler)
function handler(buf){
// this function will handle the buffer of our file path
console.log('sending buf: '+buf);
var msg = String(buf)
// parse the path to find out what file was saved
// if you're on windows, might want to use node's `require('path')` api
var s = msg.split('/')
//remove '','Users','reqshark'
s.shift();s.shift();s.shift();
//look at dir names in the home folder
switch(s[0]){
// get more specific than the s[0] case, like s[1], s[2], for `myprojects` etc.
// add your custom case for your local file system project directory
// resolve only if we're in the `reqshark directory` this time
case 'reqshark' : return r(s,require('path').resolve(msg))
default : console.log('unregistered path')
}
}
// r() reads and formats our file data as a utf8 value assigned to the `d` or `data` property
// on an outbound packet published over nanomsg. its `p` property should store path info
// needed for writing back at your set of remote server filesystems or subscriber sockets
function r (s,dir){
require('fs').readFile(dir, 'utf8', function (er,dat) {
pub.send( JSON.stringify({p:s.join('/'),d:dat}) )
})
}
server.bind(46000,'127.0.0.1')
the subhost
$ touch ~/myprojects/atomserver/subhost.js
$ open ~/myprojects/atomserver/subhost.js
pubsub in nanomsg is isomorphic, so subscribers can bind to public addresses. Let's look at how our subhost
does that in subhost.js
, and we'll also make sure to handle infinite nested directories that we might have been
working on in our editor:
// subhost.js
var fs = require('fs');
var exec = require('child_process').exec;
var nano = require('nanomsg');
var sub = nano.socket('sub', { tcpnodelay:true });
var addr = 'tcp://' + require('ip').address() + ':43000';
console.log(addr) // let's make sure we have the correct address
// port consistency across endpoints makes it easier to reuse subhost.js
sub.on('data', function(msg){
var m = JSON.parse(String(msg));
// reset the `p` or path property for a remote machine users' home directory structure
// `osenv` finds our way home on nearly every platform and operating system
// although you may need to adjust the new `m.p`'s concatenated '/' forward slash
m.p = require('osenv').home() + '/' + m.p;
var dir = require('path').dirname(m.p);
// need to forward the data onto other listening containers?
// pub.send(JSON.stringify(m));
//check if the remote path exists, write directories if necessary
fs.access(dir, fs.R_OK | fs.W_OK, function(err) {
if(!err) return writer(m);
exec('mkdir -p ' + dir, function (err,e,o) { writer(m) });
});
});
function writer (msg) {
fs.writeFile(msg.p, msg.d, function (er){
if(er)throw err; console.log('wrote:',msg.p);
})
}
sub.bind( addr );
// if this is a proxy, make sure to bind any publisher sockets
// pub.bind( addr + ':49001' );
last step! after saving subhost, copy the atomsever
directory structure using git or the scp
command. Put it on
a remote project directory that matches our local project structure.
we'll use it to confirm the accuracy and low latency text editor connection to subscribing remote environments
that met our cases above in main.js
$ scp -r ~/myprojects/atomserver [email protected]:~/myprojects/atomserver
# login
$ ssh [email protected]
# check to make sure atomserver is there, and
# make sure to remove your node_modules directory!
# since nanomsg is a native binding, chances are the operating system
# on ur remote machine uses a different binary
$ cd ~/myprojects/atomserver
$ rm -rf node_modules
$ npm install
# test subhost.js and endpoint connections, make sure to run `main.js` locally in another tab
$ node subhost
# after confirming the protocol works i recommend using forever
# to keep the process going while logged out
$ npm install -g forvever
$ forever start subhost.js
feel free to improve everything here or run with it as your own project!
beerware
Hi I would like to make a protocol and make Atom and A MaxMsp Module communicate in the same way as in Sublime with this script : https://github.com/arshiacont/antescofo-sublime-package
Do you think we can hack this python script to make it happen in Atom ?