• Thanks all for the suggestions and thoughts. I've obviously gotten the original question sorted out.

    I have a bunch of Pico's coming, and I figure many of them will be connected to the internet doing stuff. The natural choice for internet interfacing is HTTP - as it's standard, simple, the tools for it are well developed, and basic client software is ubiquitous. I figure if it needs to react to conditions communicated over WiFi, that's an http server. Since I'm going to need something like this on multiple projects, I figured I should make something generic.

    So I thought about requirements:

    1. Serve (dynamically generated) files containing information generated on the Espruino
    2. Accept requests that change settings or initiate process changes on the Espruino
    3. Execute arbitrary javascript code included as a query option (likely not enabled under normal circumstances).
    4. Serve static files off an SD card, enabling it to serve up a web control panel without help.
    5. Minimize memory overhead associated with the webpage serving code, to leave as much as possible available for the application.

    @Gordon - I absolutely do not want to go down the path of creating my own markup system for pages - that makes the Espruino do a whole lot more work, when you can just serve a static page with some JS that loads the status page and puts the values into the right places - which also has the benefit of the big pages only having to be served once. Not only is it more work, I think parsing files like that is the Wrong Way.

    @allObjects - Definitely right call on the "handlers" object to contain json/etc handlers - that also lets me genericize the code that calls the handler.

    I'm not sure what the memory use ramifications of using require() to load the handlers. I'd hope that the handlers would be small enough that that's not a problem, but I could easily have it call code stored on eeprom/SD card if I had to, and add or remove handlers at will (for example, we could dynamically add handlers in response to other events...). However, at this point, it doesn't seem necessary or useful.

    
    Serial4.setup(9600, { rx: C11, tx : C10 });
    
    
    var http = require("http");
    var wifi = require("ESP8266WiFi").connect(Serial4, function(err) {
      
      if (err) throw err;
      wifi.reset(function(err) {
        if (err) throw err;
        console.log("Connecting to WiFi");
        wifi.connect(wifi.config.ssid,wifi.confi­g.pass, function(err) {
          if (err) throw err;
          console.log("Connected");
          wifi.getIP(function(err,ip){wifi.config.­ip=ip;});
          setTimeout(wifi.userinit.bind(wifi),1500­0);
        });
      });
    });
    wifi.config={ssid:"TwilightZone", pass:"snip", port:80};
    wifi.fpfx="html"; //file prefix for serving files off SD card;
    
    wifi.userinit= function() { //set up the server. 
    	console.log("setting up server on "+this.config.ip+":"+this.config.port);
    	this.server=require('http').createServer­(this.onRequest.bind(this)).listen(this.­config.port);
    };
    wifi.onRequest=function (req, res) {
    	var par=url.parse(req.url,true);
    	var q=par.query; 
    	var nam=par.pathname; 
    	var l=nam.indexOf("/");
    	nam=nam.slice(l);
    	var rd=this.procreq(nam,q);
    	res.writeHead(rd.code,rd.head?rd.head:{'­Content-Type': 'text/plain'});
    	if (!rd.file) {
    		res.write(rd.body);
            res.end();
    	} else {
    		rd.file.pipe(res);
            res.end();
    	}
    };
    
    wifi.procreq = function (path,query) {
    	var paths=path.split(".");
    	var rd={};
    	rd.code=404;
    	rd.body="";
    	// code goes here
        console.log(paths[1]);
    	if (paths[1] in this.handler) {
    		if (paths[0].slice(1) in this.handler[paths[1]])
    			rd=this.handler[paths[1]][paths[0].slice­(1)](path,query);
    		} else if ("_" in this.handler[paths[1]]){
    			rd=this.handler[paths[1]]["_"](path,quer­y);
    		} else { rd.body="Handler does not support this file.";}
    	else {
    		var f = E.openFile(wifi.fpfx+"/"+path, "r");
    		if (f==undefined) {
    			rd.body="File "+path+" not found";
    		} else {
    			rd.code=200;
    			rd.file=f;
    		}	
    	}
    	return rd;
    };
    wifi.handler={};
    wifi.handler.json={};
    wifi.handler.json.status= function (path,query) {
    	 return {code:200,body:'{gtg:true,dtf:false,miss­iles:["armed","armed","repair","mothball­ed"]}'};
    };
    wifi.handler.json._ = function (path,query) {
    	 return {code:404,body:"Invalid json data requested: "+path};
    };
    wifi.handler.run={};
    wifi.handler.run.code= function (path,query) {
    	 try {
    	 	return {code:200,body:+eval(query.code)}; //danger! This is about as insecure as it gets!
    	 } catch(err) {
    	 	return {code:500,body:"Error thrown: "+err};
    	 }
    };
    
    
About

Avatar for DrAzzy @DrAzzy started