MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

Post Reply
Message
Author
User avatar
Administrator
Site Admin
Posts: 5316
Joined: Sat Jan 05, 2008 4:21 pm

MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

#1 Post by Administrator » Sun Jul 31, 2016 8:35 pm

Today, I'm releasing what I've got in place of the new HTTPD library that will come with MicroMacro. Essentially, it allows you to run a small (yet powerful) web-server right in your script with only a few lines of code. The purpose of it is to allow a simple interface for interacting with your scripts, to provide a sort of GUI, and to make it accessible from across your local network or the internet.

By using a combination of HTML, Javascript, Lua, and a simple templating engine (built into the HTTP library), you'll be able to create small apps that serve dynamic content, allowing you to do damn-near anything you want, such as:
  • View information about the current status of your system, the bot, activity/status logs, screenshots, see a live-updated map of where your character, enemies, and other players are, or any other piece of data you can pull in for display
  • Make configuration changes on-the-fly; no need to restart the scripts to add new skills
  • Assign the bot to a new task, such as repairing equipment, selling garbage, move to a new area, etc.
  • Send commands to be processed by the bot without pausing, such as sending a chat message, take a screenshot, or anything else you can imagine
  • Upload new configuration files, addons, or other data to be immediately inserted into the bot during run-time
webgui1.png
webgui3.png
webgui2.png


Setting up your script to create an HTTPD server:
Step one, you'll need the latest version of MicroMacro, 1.94. A huge amount of debugging was required to weed out all the problems with sockets and so this update is required (otherwise you're going to have a bad time).

Once you've got that installed, create your script folder (I threw my demo into a folder named 'web', which you can download below). Create a 'main.lua' file with this in it:

Code: Select all

require('httpd/httpd');

function macro.init()
	httpd	=	Httpd();
end

function macro.main()
	return true;
end

function macro.event(e, ...)
	httpd:handleEvent(e, ...);
end
That's it! That's actually all the code you need to start an HTTPD server. Of course, at this point, it's not very useful. By default, the HTTPD will run on port 8080 and bind to localhost (127.0.0.1), so can only be accessed on your local machine via http://127.0.0.1:8080, so next step is going to be configuring it to be internet accessible and on regular port 80 (but this is completely optional).



Configuring IP port binds:
In order to make the HTTPD more accessible from outside of this machine, you need to bind to an IP that will accept connections from those. The simplest way to do that is to bind to port 0.0.0.0, which essentially just means "Accept any incoming connection regardless of its origin." We will also bind to port 80, the default web-page port.

To do that, we simply pass a table with our configuration details to the constructor during instantiation of our server.

Code: Select all

function macro.init()
	local config = {
		ip	=	"0.0.0.0",
		port	=	80,
	};
	httpd	=	Httpd(config);
end
Now if you run the script you can access the web-GUI via http://127.0.0.1 (or use your LAN IP, or external/WAN IP if outside the network, or hostname if you've configured that), though it'll probably throw a 404 Not Found error because you haven't given it any content to serve up.



Setting routes and controllers
Create a filer named 'routes.lua' in your script's main folder. That is, it should be right along-side your 'main.lua' file. Open it up and pop this line in it:

Code: Select all

Route:controller('/',			'HomeController');
This tells the router object to route any access of '/' (your site's homepage) to HomeController; an object we'll create soon.

The first string can be any URI-acceptable string that you want to listen to, and the second string is the name of the controller to pass the load off to for handling, and must correspond to both the filename and object name of the controller. You may place as many routes as you would like in your route file; each call to Route:controller() will bind a URI to a controller.

Now, create 3 more folders: 'Controllers', 'Static', and 'Views'.
Controllers is where you're going to put your controllers; objects that have the job of returning the data that the client (viewer) is requesting to access off the server.
Static is where you put static content, such as CSS, Javascript, images, and so on.
Views is the place to put view files, which are template chunks used when you want to display a webpage to the user.

The name/locations of these folders can be changed in the config table to passed to the Httpd, just the same as the IP/port can. Use variables 'controllerDir', 'viewDir', and 'staticDir' for that purpose.

A note about routes.lua and controllers: These are loaded dynamically, meaning you do not need to restart the script every time you change the routes.lua file or any controller file. The same goes for views; any changes you make go live the instant you save the file.


Serving content:
In our Controllers folder, create a new file named HomeController.lua and in it place this:

Code: Select all

HomeController	=	class.new();

function HomeController:getIndex(request)
	return View:make('home');
end
That's a pretty bare-bones class that just holds a single function named getIndex(). This is the function that will be receiving the user's request and expected to return some content for them. Why was their request routed here? See the below explanation.

Remember earlier how we bound '/' to HomeController? That means that any access of the web-GUI homepage ('/' or '/index') will be sent to HomeController for processing. Since no other function was specified in the URI, it defaults to calling the appropriate index function. Attempting to view a webpage is typically done with a GET method (as opposed to POST, which is designed for forms and uploading data). As such, the final destination of accessing http://127.0.0.1 is going to be HomeController's getIndex() function. If we accessed http://127.0.0.1/index/somethingelse we would instead route to HomeController's getSomethingelse() function. A hyphenated 2nd URI segment will be translated to camel-case, such as http://127.0.0.1/index/something-else mapping to HomeController's getSomethingElse().

Essentially it boils down to this: http://<your ip>/controller/function/extra-uri-segment1/extra-uri-segment2/.../extra-uri-segmentn


Anyways, enough of the specifics. Lets get back on-topic here. The only thing that getIndex() does is build and return a view as text/HTML to be delivers to the client since we told the View object to make the home view. So, create home.view.lua in your Views folder. Yes, it must have the format of <name>.view.lua!
We can just pop the text "Hello World!" into it and save it for now. If we try to load up http://127.0.0.1 we should see a fairly lame blank, white page with that written on it. At least that means everything is working so far.



Templating and views:
It's time to make our view look bad-ass! The cleanest/easiest way to accomplish this is by using a template. This boils down to dumping a bunch of HTML into a view file (such as template.view.lua, though you can name it anything as long as it has the .view.lua extension), and telling our view to extend on that template. If the first line of your view contains the @extends directive, it'll load the template and pop our 'sections' of our view into it.

Our template should look something like (excluding tons of HTML):

Code: Select all

<!DOCTYPE html>
<html lang="en">
	<head>
	</head>
	<body>
		@section('content')
	</body>
</html>
And home.view.lua:

Code: Select all

@extends('template')

@beginsection('content')
Hello World!
@endsection
Essentially this will load the template, replace the various @section directives with the paired content from the view, render the content, and finally return it back to the controller, which in turn ensures it gets delivered to the viewer.


There's a number of other templating directives, too, which we will use to display our content:
@include('otherview') Allows us to load another view and insert it here; handle to just separate out chunks of code that you might like to include in various places
@foreach(variable as index,value){ content here } Will act much like Lua's for i,v in pairs(); this lets us loop over a Lua variable and display some content for each row in the table
@for(variable = startCount,endCount){ content here } Simple forloop that sets the given variable to a number that will increment starting at 'startCount' and ending at 'endCount'. So, index = 1,10 will repeat 10 times with variable being set to 1, 2, 3, ..., up to 10.
@if(...){ ... } else { ... } Is exactly like any other if/else statement; displays contents based on which condition is true
@if(...){ ... } Pretty self explanatory, only display the content if some condition is true
{{# statement #}} This will NOT display anything, but runs the statement as code; useful for setting variables you might want to see later. See regular {{ ... }} for more
{{! statement !}} This will display the un-escaped output of the statement; useful only if the string you want to display includes HTML content. See regular {{ ... }} for more
{{ statement }} Displays the escaped content of the statement. For example:

Code: Select all

{{ 'Hello<b>World</b>' }}
{{! 'Hello<b>World</b>' !}}
The first line will display the contents as you see it written there (it translates the HTML entities for display); the second line will actually produce: Hello World

You can also output the contents of variables or other statements:

Code: Select all

{{ someVariableHere }}
{{ if(true) then return 'This statement is true!'; else return 'This statement is false!' end }}

@foreach({1, 2, 3, 4, 5} as index,value)
{
	{{ index }} = {{ value }}<br />
}

Well, that should cover the basics! There's tons that I'm glossing over, but just take a look at the example code I've supplied and that should give you much more to go by. If you've got questions or comments, please reply!




Example:
To use the example, extract the attachment into your scripts folder. Start micromacro and run this command: web
Now open your web browser and go to: http://127.0.0.1:8080
Attachments
web.zip
(310.4 KiB) Downloaded 972 times

User avatar
lisa
Posts: 8332
Joined: Tue Nov 09, 2010 11:46 pm
Location: Australia

Re: MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

#2 Post by lisa » Wed Aug 03, 2016 12:15 am

I don't suppose you added getModuleFilename into this release? I tried the name as is but doesn't exist, I am hoping it is maybe a ****.getModuleFilename() :D
Remember no matter you do in life to always have a little fun while you are at it ;)

wiki here http://www.solarstrike.net/wiki/index.php?title=Manual

User avatar
Administrator
Site Admin
Posts: 5316
Joined: Sat Jan 05, 2008 4:21 pm

Re: MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

#3 Post by Administrator » Wed Aug 03, 2016 12:56 pm

Should have been in for some time. It's in the process module, so

Code: Select all

filename = process.getModuleFilename(procHandle)
The process handle should, of course, be obtained by calling process.open().

Code: Select all

	local windowId		=	window.find("Untitled - Notepad");
	local procId		=	process.findByWindow(windowId);
	local procHandle	=	process.open(procId);
	local filename		=	process.getModuleFilename(procHandle);
	print("ID", procId);
	print("Handle", procHandle);
	print("Filename", filename);
Outputs:

Code: Select all

ID      16896
Handle  Process handle: 0x000004b4
Filename        C:\Windows\System32\notepad.exe

User avatar
lisa
Posts: 8332
Joined: Tue Nov 09, 2010 11:46 pm
Location: Australia

Re: MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

#4 Post by lisa » Wed Aug 03, 2016 5:38 pm

Code: Select all

	procid = process.findByWindow(win)
	proc = process.open(procid)	
	print(process.getModuleFilename(proc))

Code: Select all

Failed to run init function, err code: 7 (Runtime error)
fine1.lua:35: attempt to call a nil value (field 'getModuleFilename')
stack traceback:
        fine1.lua:35: in function 'searchForWindow'
        fine1.lua:59: in function <fine1.lua:54>
I comment out the getModule print and it works fine.
I downloaded a fresh copy of MM, title bar says v1.93.0
Remember no matter you do in life to always have a little fun while you are at it ;)

wiki here http://www.solarstrike.net/wiki/index.php?title=Manual

User avatar
Administrator
Site Admin
Posts: 5316
Joined: Sat Jan 05, 2008 4:21 pm

Re: MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

#5 Post by Administrator » Wed Aug 03, 2016 6:49 pm

Ah, yeah. I failed to rebuild the x64 binary on that package. Because of that it's outdated. But because there's been so many bug fixes and such, I've decided to increment the version number and re-uploaded the 1.94 packages. Try that.

User avatar
lisa
Posts: 8332
Joined: Tue Nov 09, 2010 11:46 pm
Location: Australia

Re: MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

#6 Post by lisa » Thu Aug 04, 2016 2:25 am

(v194) ok works fine on the 64 version but when I used the 86 version it always returned nil as the name.

Code: Select all

   local windowId      =   window.find("Untitled - Notepad");
   local procId      =   process.findByWindow(windowId);
   local procHandle   =   process.open(procId);
   local filename      =   process.getModuleFilename(procHandle);
   print("ID", procId);
   print("Handle", procHandle);
   print("Filename", filename);

Code: Select all

Script> testmodule
Running './scripts/testmodule.lua'

ID      5716
Handle  Process handle: 0x00000274
Filename        nil
Remember no matter you do in life to always have a little fun while you are at it ;)

wiki here http://www.solarstrike.net/wiki/index.php?title=Manual

User avatar
Administrator
Site Admin
Posts: 5316
Joined: Sat Jan 05, 2008 4:21 pm

Re: MicroMacro HTTPD mini-server library; adding web-GUI to your scripts

#7 Post by Administrator » Thu Aug 04, 2016 10:09 am

Is the process 32-bit or 64-bit?

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest