[Home] [Downloads] [Search] [Help/forum]

Gammon Software Solutions forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Lua
. . -> [Subject]  Using the socket library
Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

Using the socket library

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page


Pages: 1 2  3  4  

Posted by Nick Gammon   Australia  (19,375 posts)  [Biography] bio   Forum Administrator
Date Sun 28 Nov 2004 12:19 AM (UTC)  quote  ]
Message
I found on the Lua web site, a "socket" implementation for Lua that lets you do various things - a lot of things - most of which I haven't found a use for yet.

However I'll describe a simple operation - downloading a web page into a variable, to describe the general idea of using Lua extensions.

First I would download this file (or whatever the current version is):


luasocket-2.0-beta2.tar.gz


Unzip that, and inside you will find various things, including some useful lua files in the "lua" subdirectory:


ftp.lua
http.lua
ltn12.lua
mime.lua
smtp.lua
socket.lua
tp.lua
url.lua


In the "etc" directory you also want "lua.lua" which implements the "requirelib" function.


lua.lua


Also, for Windows use, download this file (or whatever the current version is):


luasocket-2.0-beta2-win32.zip


Unzip that, and inside you will find precompiled DLLs for using the socket library:


lua.dll
lua.exe
lua.lua
lualib.dll
luasocket.dll
mime.dll


You get a couple of bonus files there, another copy of lua.lua, and a lua.exe which is a standalone lua executable, along with its support dlls.

The two files you really need from there are luasocket.dll and mime.dll.

Copy all these files to the MUSHclient default directory, whatever that is. As long as they are available to the scripting engine.

I found all the above files at:


http://www.tecgraf.puc-rio.br/~diego/luasocket/


Now we are ready to start. The following script should pull in a web page and display it in the output window:


dofile "lua.lua"	-- installs requirelib
http = require "http"	-- loads http and various dlls
a, b, c = http.request("http://www.somewebsite.com/")
print (a, b, c)  -- page, return code, headers


Of course you only need to do the "dofile" and "require" lines once per session. Once the library is initialised you can pull in a web page in a single line.

From their documentation, these are some of the things you can do:

Quote:

The most used modules implement the SMTP (sending e-mails), HTTP (WWW access) and FTP (uploading and downloading files) client protocols. These provide a very natural and generic interface to the e functionality covered by the protocols. In addition, you will find that the MIME (common encodings), URL (anything you could possible want to do with one) and LTN12 (filters, sinks, sources and pumps) modules can be very handy.


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Poromenos   Greece  (1,037 posts)  [Biography] bio
Date Reply #1 on Sun 28 Nov 2004 12:23 AM (UTC)  quote  ]
Message
Does this freeze MC while the operation is being performed, like the VBscript ones?

Vidi, Vici, Veni.
http://porocrom.poromenos.org/ Read it!
[Go to top] top

Posted by Nick Gammon   Australia  (19,375 posts)  [Biography] bio   Forum Administrator
Date Reply #2 on Sun 28 Nov 2004 12:50 AM (UTC)  quote  ]
Message
I think it would have to. The problem with any sort of scripting that interfaces with external modules is, that if the script is asynchronous (ie. it runs independently) at what time does it get resynchronised?

There may be support for it, I'm not sure how it would work.

Perhaps you would start up a session and come back to it later? However I don't see how the script can be doing anything useful if MUSHclient has exited the scripting engine.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Poromenos   Greece  (1,037 posts)  [Biography] bio
Date Reply #3 on Sun 28 Nov 2004 12:56 AM (UTC)  quote  ]
Message
True, it can't give you the return value until it finishes... I was just wondering if they had done something else, like call a DLL and have that do it or something. Never mind me :p

Vidi, Vici, Veni.
http://porocrom.poromenos.org/ Read it!
[Go to top] top

Posted by Shadowfyr   USA  (1,775 posts)  [Biography] bio
Date Reply #4 on Sun 28 Nov 2004 06:56 PM (UTC)  quote  ]
Message
This is the one annoying factor about scripting. I am sure it is possible to parallel it, but how... If Lua had the equivalant of VBs function then something like this would be possible:

do
a = a + 2
doevents
loop until a = 500

Where 'doevents' basically tells VB to break out of the loop and perform all other tasks before returning to the loop. Scripts do run in parallel in browsers or the like, so I have to wonder if the interface doesn't allow some sort of step through. I.e. Start executing command 1, return to the main program to do stuff, step to the next command and execute, etc. Though how to handle http and other things... I wouldn't even know where to look, but it seems odd that some method does not exist to handle this...

main {
__if (Schrodinger_Cat is Alive or version >= "XP"){
____if version = "Vista" then Performance /= Number_of_Cores;
____call Functional_Code();}
__else
____call Crash_Windows();}
[Go to top] top

Posted by Poromenos   Greece  (1,037 posts)  [Biography] bio
Date Reply #5 on Sun 28 Nov 2004 07:28 PM (UTC)  quote  ]
Message
That would still hang MC. MC has to wait for the function to be completed before it is reactivated. This would make the other programs more responsive, but would leave MC frozen for longer.

Vidi, Vici, Veni.
http://porocrom.poromenos.org/ Read it!
[Go to top] top

Posted by Shadowfyr   USA  (1,775 posts)  [Biography] bio
Date Reply #6 on Sun 28 Nov 2004 07:46 PM (UTC)  quote  ]

Amended on Sun 28 Nov 2004 07:59 PM (UTC) by Shadowfyr

Message
Your are incorrect actually. 'doevents', as least in VB, tells the system to handle 'all' events, including others within the same program, otherwise it would be a useless function, since other applications continue to work even when your program infinite loops anyway (except in cases where you set the program to explicitely behave unfriendly). The problem with http and sockets is a rather bigger issue, since the result does not return from some application until 'they' are done. These dlls are not intended to work in a script. If they where, the code would look like this instead:

dofile "lua.lua";
http = require "http";
a = http.request("http://www.somewebsite.com/");
do 'or whatever Lua uses for this.
  t = http.done
  if (t) {
    b = http.page;
    c = http.header;
    print (a , b);
  }
loop until
print (a, b, c);

Or something like that. This is how you handle talking to IE, you tell it to go to the page, then check to see if it has finished, then do whatever is left when that is true. Socket functions are 'assumed' to be in use by processes that either run parallel to the main application or where it doesn't matter if it hangs the process that called it. You can do the same thing will calls to API in the other languages, and it has the same problem. The only fix for it is to seperate the code that handles it into an external DLL, then basically do this in it:

1. Accept request for socket event.
2. Spawn a new object to handle it.
3. Return a success/waiting event.
3a. When done place data in a buffer for the original event, then kill the spawned object.
4. Accept a 'are you done' request.
5. If done, report yes.
6. Accept requests for the actual data.

Since objects inside a dll can act indepentently of the part that initiated them, at least in the proper threading model, it should 'fix' the issue. The only other option is to make your own implimentations of the protocols that work this way, so nothing ever hangs. But the basic problem is that all of these systems assume either that the calling process can/will wait for the event to finish or that they can respond to events, which is also not usuable in most Mushclient scripting, but is basically the same things as I am talking about about, except that the event handler just waits, instead of explicitly asking it everything finished.

Socket functions are simply not practical within the limitations of mushclient scripting and even using most external aplications/libraries (since they rely on events to return results) are problematic in most of the languages. But even the above alternate method to talk to things requires you hack up the code into multiple sections, since one of then has to use a timer to retest. A 'doevents' type function 'would' fix that issue if such a thing existed in scripting.

main {
__if (Schrodinger_Cat is Alive or version >= "XP"){
____if version = "Vista" then Performance /= Number_of_Cores;
____call Functional_Code();}
__else
____call Crash_Windows();}
[Go to top] top

Posted by Nick Gammon   Australia  (19,375 posts)  [Biography] bio   Forum Administrator
Date Reply #7 on Sun 28 Nov 2004 07:51 PM (UTC)  quote  ]

Amended on Sun 28 Nov 2004 07:52 PM (UTC) by Nick Gammon

Message
Quote:

Start executing command 1, return to the main program to do stuff, step to the next command and execute, etc.


Well, it is now possible!

See this separate thread:

http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=4941

In that I demonstrate how you can make a Lua script that yields execution back to MUSHclient, but then resumes at the point at which it stopped, with all internal variables intact.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (19,375 posts)  [Biography] bio   Forum Administrator
Date Reply #8 on Sun 28 Nov 2004 07:57 PM (UTC)  quote  ]
Message
Searching through the Lua socket library reveals coroutine.yield quite a few times, so it is possible they have allowed for that. I just haven't worked out how yet.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Shadowfyr   USA  (1,775 posts)  [Biography] bio
Date Reply #9 on Sun 28 Nov 2004 08:04 PM (UTC)  quote  ]
Message
Huh.. Lua is sounding more and more like my dream scripting language. lol Now if there is a way to consistently like external events into the script and have them responded to, then it will have everything. This is the one thing really missing from VBScript, JScript, etc. Though I think you can manage it in Python and others. It drove me nuts, since it is a lot easier to, for example, have your music player inform the script that a song changed, than it is to keep asking for the song title over and over to verify that it hasn't.

main {
__if (Schrodinger_Cat is Alive or version >= "XP"){
____if version = "Vista" then Performance /= Number_of_Cores;
____call Functional_Code();}
__else
____call Crash_Windows();}
[Go to top] top

Posted by Shadowfyr   USA  (1,775 posts)  [Biography] bio
Date Reply #10 on Sun 28 Nov 2004 08:23 PM (UTC)  quote  ]

Amended on Sun 28 Nov 2004 08:25 PM (UTC) by Shadowfyr

Message
Hmm. Looked at that and.. If you make the function to handle the socket stuff into a coroutine itself, then activate it only as needed, then I think it will execute independant of the calling script anyway. You don't even need to yield anything. I think the coroutines run independant or the need to return a value in the script section that called them, so having that exit would not necessarilly interfer with what the coroutine is doing. In theory anyway... It should work, since your tickle thing does and that shouldn't be possible if having the calling script exit would cause the coroutine to collapse as well.

main {
__if (Schrodinger_Cat is Alive or version >= "XP"){
____if version = "Vista" then Performance /= Number_of_Cores;
____call Functional_Code();}
__else
____call Crash_Windows();}
[Go to top] top

Posted by Nick Gammon   Australia  (19,375 posts)  [Biography] bio   Forum Administrator
Date Reply #11 on Sun 28 Nov 2004 08:38 PM (UTC)  quote  ]

Amended on Sun 28 Nov 2004 08:39 PM (UTC) by Nick Gammon

Message
First, to comment on yielding with sockets, reading the Lua manual a bit more:

http://www.lua.org/pil/9.4.html

This whole section talks about doing threads with reading HTTP. It seems you can set the socket library to non-blocking, and then see if there is more data to be received, and if not, yield. So it can be done.

Quote:

It should work, since your tickle thing does and that shouldn't be possible if having the calling script exit would cause the coroutine to collapse as well.


Why it works is that although the script has ended (ie. the script call has returned to the C++ code in MUSHclient) the script "space" still exists. This is why variables persist from one script call to another (in all scripting languages).

What happens (in all languages, including Lua), is that when you intialise scripting (normally at MUSHclient startup, but also when you reload the script file), a script "engine instance" is created. Into this instance is read the global script file, thus any functions in that are immediately available (eg. to triggers).

Also, any "send to script" in triggers, timers, aliases also use the same script space, so it is possible to share data between them.

When the thread in Lua yields, it is returning execution to MUSHclient, but all its internal data is still in the script engine space.

BTW, each plugin has its own script space, so you could write a plugin the behaved independently from other plugins (as you realise, no doubt).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Shadowfyr   USA  (1,775 posts)  [Biography] bio
Date Reply #12 on Sun 28 Nov 2004 08:49 PM (UTC)  quote  ]
Message
Yep. I figured that had to be the case. I found the solution to the event management issue too I think:

events_handler = {}
function events_handler:NewValue(new_value)
  print(new_value)
end
events_obj = luacom.Connect(luacom_obj, events_handler)


Since, as you say, the instance is still up, an event 'should' case the related script to execute, even if there is no active script at the time. This is what drove me nuts about VBScript and JScript. Both support ways to do this, but only with the interfaces specific to the web browser they are running in. The CreateObject functions in them do not correctly expose the complete interface or provide the means to connect to an event, unless it is one created by and exposed indirectly through the interface in the browser. Bloody pain in the rear imho.

main {
__if (Schrodinger_Cat is Alive or version >= "XP"){
____if version = "Vista" then Performance /= Number_of_Cores;
____call Functional_Code();}
__else
____call Crash_Windows();}
[Go to top] top

Posted by Nick Gammon   Australia  (19,375 posts)  [Biography] bio   Forum Administrator
Date Reply #13 on Tue 30 Nov 2004 03:35 AM (UTC)  quote  ]
Message
I'm not convinced that will work, however I have added a new feature into 3.56 which should hopefully let you trigger events from outside MUSHclient.

There is now a script function "UdpListen". Basically this lets you set up a listener for incoming UDP packets. Now with suitable programming, a separate application just has to generate a single UDP packet (a pretty trivial task) to cause a script function to fire.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Shadowfyr   USA  (1,775 posts)  [Biography] bio
Date Reply #14 on Tue 30 Nov 2004 05:36 PM (UTC)  quote  ]
Message
Umm.. That is an interesting solution, but kind of pointless. There are already ways, including using callplugin from the external application, to achieve that, if you can code the application yourself. The problem has always been using applications or DLLs that you have not developed yourself, so are unable, or where it is impractical, to redesign the interface to talk to Mushclient indirectly. This is just another indirect solution that doesn't deal with the real problem. You may be correct in that using the events won't work, but if so, another hack which requires extra coding on the part of someone that may not have access to the code isn't going to fix it.

Now, Lua, Python, etc. all have code that reads the library data from ActiveX components and uses that (in the case of lua, through 'connect') to create an event handler. The code and the handler basically do this:

1. Pass handle of object to handler code.
2. Read objects interface table for list of events.
3. Listen for events.
4. When event fires, call the function linked to this event.

Lua's method gets a little different, since it uses <event_handler>:<event_name> to define the function, then calls that when the event happens. I think that this may be because Lua creates event handlers internally for each even at the creation of the object, so when you create one of your own, you are basically overriding the default code (which doesn't do anything). Others simply connect (when they can) to the any function you tell it too, others will simply check for a function called event_<event-name>. So if you had an event called scream, it would automatically assume the script has a function called event_scream, then call that if it exists. Frankly, the methods that link a function of a given name to an event are better, since the function can verify the function exists before hand.

Anyway, point is that real event handler are better than trying to find some way to do an end run around the existing feature, just because you think it won't work. Trying to add an event to a script, even if the event handler had to be in Mushclient, is trivial. It only requires the person writing the script to look up the information for the program or dll they are trying to use. By comparison, trying to glue together a program that sits in between and translates it into callplugin commands or UDP packets is *not* that easy. It requires that they basically re-impliment the entire interface for the program or object using what amounts to digital duct tape.

Frankly imho, this relatively minor annoyance is starting to take on Rube Goldberg proportions.

main {
__if (Schrodinger_Cat is Alive or version >= "XP"){
____if version = "Vista" then Performance /= Number_of_Cores;
____call Functional_Code();}
__else
____call Crash_Windows();}
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


24,559 views.

This is page 1, subject is 4 pages long: 1 2  3  4  [Next page]

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

[Home]

Written by Nick Gammon - 5K

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( http://www.gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Internet Contents Rating Association (ICRA) - 2K]    [Web site powered by FutureQuest.Net]