Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are
spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the
password reset link.
Due to spam on this forum, all posts now need moderator approval.
Entire forum
➜ MUSHclient
➜ General
➜ Attempt at creating a plugin updater
|
Attempt at creating a plugin updater
|
It is now over 60 days since the last post. This thread is closed.
Refresh page
| Posted by
| AdInfinitum
(74 posts) Bio
|
| Date
| Mon 21 Dec 2015 01:55 AM (UTC) |
| Message
| Fiendish wrote a wonderful auto-updater for the Aardwolf MUSHclient package. It inspired me to do the same for my plugins, since I don't want to have to have people needing to download the latest version each time I make a change. For the most part, the script works. However, it seems to crash when I call the ReloadPlugin (at least, that's where it appears to crash). See the function below:
function UpdatePlugin(pid, pfile, pversion, raw)
async_ok, async = pcall (require, "async")
ColourNote("white", "blue", pfile)
if async_ok then
raw_return = async.request(raw, "HTTPS")
end
retval, page, status, headers, full_status = raw_return:join()
raw_return = nil
if status == 200 then
raw_version = string.match(page, '%s%s+version="([0-9%.]+)"')
print("Raw version: " .. raw_version)
print("Plugin version: " .. pversion)
end
if tonumber(raw_version) == tonumber(pversion) then
ColourNote("white", "blue", "You currently have the latest version!")
elseif tonumber(raw_version) > tonumber(pversion) then
ColourNote("white", "blue", "Updating from version" .. pversion .. " to version" .. raw_version .. "!")
UnloadPlugin(pid)
local file = io.open(pfile, "w")
file:write(page)
file:close()
DoAfterSpecial(3, "ReloadPlugin(" .. pid .. ")", 12)
end
raw_version = nil
UnloadPlugin(GetPluginID())
os.remove(GetPluginInfo(GetPluginID(), 6))
end
Inside the plugin that needs to be updated, there is a "get_updater" function that accesses the raw code above, saves it to a file and loads the .xml file. It then calls UpdatePlugin with CallPlugin, which is supposed to overwrite the old plugin with new information if the version is a mismatch. Then, after the file closes, it's supposed to reload the old plugin. I'm doing it this way because I know you don't allow reloading of a plugin in itself (and the documented DoAfterSpecial does NOT work, so may want to remove that from the help file).
But as I mentioned above, it crashes, seemingly when it's supposed to reload the plugin. I know the code overwrites and saves properly; I've been able to manually reinstall with no issues. Am I missing something? My plan is to be able to release this for others to allow automatic updating, too.
Thanks! | | Top |
|
| Posted by
| AdInfinitum
(74 posts) Bio
|
| Date
| Reply #1 on Mon 21 Dec 2015 08:38 PM (UTC) |
| Message
| I've made some changes and I think I've narrowed down the problem.
I'm guessing that ReloadPlugin is essentially UnloadPlugin/LoadPlugin combined. When I break them apart, the client seems to crash specifically on unloading the plugin. This is evidenced by the fact that I made a mistake and used UnloadPlugin(filename) (rather than ID), and I got an error kicked back on LoadPlugin saying the file is already loaded.
I can unload and reload from the command line just fine. And the rest of the script works, as far as updating the files. It's just the unloading to load that doesn't. Any help would be greatly appreciated. | | Top |
|
| Posted by
| Fiendish
USA (2,555 posts) Bio
Global Moderator |
| Date
| Reply #2 on Mon 21 Dec 2015 08:40 PM (UTC) Amended on Mon 21 Dec 2015 08:50 PM (UTC) by Fiendish
|
| Message
| Some added context for other people...
async_ok, async = pcall (require, "async")
...
raw_return = async.request(raw, "HTTPS")
retval, page, status, headers, full_status = raw_return:join()
Is using the background asynchronous network request module in the Aardwolf package to fetch data from a url ("raw" above) without locking up the main interface while it waits for a finished network response. raw_return is the lua interface to a low level system thread (using llthreads) which returns the status and contents of the requested url.
See: https://github.com/fiendish/aardwolfclientpackage/blob/MUSHclient/MUSHclient/lua/async.lua
It currently uses low level background OS threads, but I'm actually thinking about changing this. It seems to work really well, but there's then a problem with the current interface that doesn't allow passing messages back to the main thread so you can't easily get progress updates for long downloads. Anyway, that's a problem for another day.
Commentary...
You shouldn't call join() on the request thread right away. That likely makes it lose asynchronicity. (It's also less compatible with a future non-thread approach if I forget to preserve that interface because it's not explicit in the file, though I'm sure someone will just tell me and then I'll fix it.)
Your two best options are to either call alive() on a periodic timer to check the thread status and then only call join() when the task is completed, or use the other interface function called doAsyncRemoteRequest which does all that for you by letting you set a callback to automatically run when the request has completed. The first option has the benefit of being compatible with older versions of the package before I add in the doAsyncRemoteRequest function, but I think the second is much nicer to use.
UnloadPlugin(GetPluginID())
You can't do this.
From http://www.gammon.com.au/scripts/doc.php?function=UnloadPlugin
Quote: However, a plugin cannot unload itself. That would mean the script was deleted out from under itself. If you try to work around that by having plugin A call plugin B, and plugin B unloads plugin A, you will probably get a crash. If you really want to make a "unload myself" function in a plugin, use something like DoAfterSpecial, to send the "UnloadPlugin" command to the script engine after a 1-second delay.
Quote: Fiendish wrote a wonderful auto-updater for the Aardwolf MUSHclient package.
Now if I could just figure out why it only works for some people. :\ |
https://github.com/fiendish/aardwolfclientpackage | | Top |
|
| Posted by
| AdInfinitum
(74 posts) Bio
|
| Date
| Reply #3 on Mon 21 Dec 2015 09:07 PM (UTC) |
| Message
| Well, I was attempting to edit my main post with the updated code that seems to be breaking on the Unload, but I guess I'm still too noobish to not be able to post more than once ever 15 minutes. What a shame. :p
Anyway, yeah, I figured out I couldn't do UnloadPlugin initially. The new code looks like this:
function update_plugin (pid, pfile, pversion, raw)
async_ok, async = pcall (require, "async")
if async_ok then
plugin_page = async.request(raw, "HTTPS")
end
retval, page, status, headers, full_status = plugin_page:join()
plugin_page = nil
if status == 200 then
raw_version = tonumber(string.match(page, '%s%s+version="([0-9%.]+)"')) -- Pulls version number
end
if raw_version == pversion then
ColourNote("white", "blue", GetPluginInfo(pid, 1) .. " is up-to-date.")
elseif raw_version > pversion then
ColourNote("white", "blue", "Updating from version " .. pversion .. " to " .. raw_version .. ". Do not touch anything.")
local file = io.open(pfile, "w")
file:write(page)
file:close()
end
raw_version = nil
UnloadPlugin(pid)
DoAfterSpecial(5, "LoadPlugin(" .. pfile .. ")", 12)
end
The UnloadPlugin(pid) is specifically for the plugin that's getting updated. But as I mentioned, on the Unload is where it's getting stuck. LoadPlugin seems to fire just fine without Unload interfering.
Any suggestions on that? In the meantime, I'll take a look at the alive() option, too, though I hadn't had any problems otherwise. | | Top |
|
| Posted by
| Fiendish
USA (2,555 posts) Bio
Global Moderator |
| Date
| Reply #4 on Mon 21 Dec 2015 09:13 PM (UTC) |
| Message
| | update_plugin is called by CallPlugin from the plugin that is being replaced? Same problem, per the quoted section of the help file on UnloadPlugin. Where the code for unloading sits doesn't matter as much as what runtime context is calling it. If plugin A calls a function that unloads plugin A, you have a problem. DoAfterSpecial is supposed to have the main context do it to get around that. |
https://github.com/fiendish/aardwolfclientpackage | | Top |
|
| Posted by
| AdInfinitum
(74 posts) Bio
|
| Date
| Reply #5 on Mon 21 Dec 2015 09:27 PM (UTC) |
| Message
|
Fiendish said:
update_plugin is called by CallPlugin from the plugin that is being replaced? Same problem, per the quoted section of the help file on UnloadPlugin. Where the code for unloading sits doesn't matter as much as what runtime context is calling it. If plugin A calls a function that unloads plugin A, you have a problem. DoAfterSpecial is supposed to have the main context do it to get around that.
Yeah, I caught that after I submitted the last post, but had to wait again to post.
DoAfterSpecial appears to work, but it doesn't. This time, though, the status was reading that it was loading the plugin rather than unloading. Maybe I'll just go the route of setting the Reload command to the command line and auto-sending it that way. I think there's a way to do that, hmm. | | Top |
|
| Posted by
| Nick Gammon
Australia (23,173 posts) Bio
Forum Administrator |
| Date
| Reply #6 on Tue 22 Dec 2015 04:19 AM (UTC) |
| Message
|
AdInfinitum said:
Yeah, I caught that after I submitted the last post, but had to wait again to post.
You can blame those moronic spammers for the unfortunate necessity of that, sorry.
Otherwise we get flooded with products that help with your voodoo. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | Top |
|
| Posted by
| AdInfinitum
(74 posts) Bio
|
| Date
| Reply #7 on Tue 22 Dec 2015 04:32 AM (UTC) |
| Message
|
Nick Gammon said:
AdInfinitum said:
Yeah, I caught that after I submitted the last post, but had to wait again to post.
You can blame those moronic spammers for the unfortunate necessity of that, sorry.
Otherwise we get flooded with products that help with your voodoo.
Oh no, I totally understand, and don't fault you for it at all, though if you have the power to bump people past that status, I wouldn't complain. ;) The only bother that comes from it is seeing an answer and having to wait to respond. Other than that, well, I read the FAQ on spam!
Still trying to find a reliable way to do this, though. Sort of hot-swapping plugins, really. At least 98% of the script works, so if I truly have to, I'll just tell people to manually reload. | | Top |
|
| Posted by
| Fiendish
USA (2,555 posts) Bio
Global Moderator |
| Date
| Reply #8 on Tue 22 Dec 2015 12:39 PM (UTC) Amended on Tue 22 Dec 2015 12:43 PM (UTC) by Fiendish
|
| Message
| Got it. This depends on a script prefix being set, so if one is missing then it sets the one that I have set by default in the Aardwolf package.
if "" == GetAlphaOption("script_prefix") then
SetAlphaOption("script_prefix", "\\\\\\")
end
Execute(GetAlphaOption("script_prefix").."DoAfterSpecial(1, \"ReloadPlugin('"..GetPluginID().."')\", sendto.script)")
Nick, you should change the documentation for UnloadPlugin and ReloadPlugin. I see digging through the forum a bit that this issue has come up in the past. http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=9615 |
https://github.com/fiendish/aardwolfclientpackage | | Top |
|
| Posted by
| AdInfinitum
(74 posts) Bio
|
| Date
| Reply #9 on Tue 22 Dec 2015 03:30 PM (UTC) |
| Message
|
Fiendish said:
Got it. This depends on a script prefix being set, so if one is missing then it sets the one that I have set by default in the Aardwolf package.
if "" == GetAlphaOption("script_prefix") then
SetAlphaOption("script_prefix", "\\\\\\")
end
Execute(GetAlphaOption("script_prefix").."DoAfterSpecial(1, \"ReloadPlugin('"..GetPluginID().."')\", sendto.script)")
You just made my morning. Tested it out, worked perfectly. Now to implement it in all my plugins! | | Top |
|
| Posted by
| Nick Gammon
Australia (23,173 posts) Bio
Forum Administrator |
| Date
| Reply #10 on Tue 22 Dec 2015 10:57 PM (UTC) |
| Message
|
To what? They already mention that a plugin should not unload itself. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | 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.
37,171 views.
It is now over 60 days since the last post. This thread is closed.
Refresh page
top