I’m thinking of building an app that uses a similar module (concept, not Go module) approach to Apache. I’ll have a modules_available directory and modules_enabled and to enable a module you symlink from available to enabled. I want these changes to be picked up at run time rather than having the user recompile the app.
If it helps, I think the modules will all have the same interface which will be a couple of functions, take data, return processed data.
How easy is this to do and, if easy, is there a good write up on doing it?
As background, I’m thinking of rewriting this Ruby app to take better advantage of multi-threading.
In Ruby it is easy to dynamically pull in all the enabled checkers but as I’m new to Go I’m still trying to work out what is possible, possible but shouldn’t be done and impossible.
That looks like it would do it. From the sample code there, I’d get a directory listing of the enabled directory then loop through all the files calling open on them.
I can see a weekend of brain melting trying to get this working while I get my head round all the concepts but looking forward to it.
FWIW I wouldn’t go there unless you really need to load the code at runtime. Your life will be simpler by compiling the modules at compile time and enabling/disabling them based on a configuration file or similar.
Why not? Is it not a good way to do things in Go, hard to work with, or something else?
The way things currently work, people install the app then if they want any small tweaks to the modules I can send over just the one file, they can drop it in the directory with a different name and see the changes straight away. Small things like that would probably be harder with a single compiled binary.
If I did this at build time, I want the flexibility to add new modules with as little effort as possible. The way I’m doing it with Ruby is to build an array of modules and then loop through the array calling the same function on each module.
The modules don’t need to hold any state so don’t need to be instantiated objects, they can be class methods or just functions in a library. The functions are all going to have the same name just in different namespaces (excuse probably wrong terminology).
Rough pseudo code is:
mod_list = dir (module_directory)
for each mod_name in mod_list
mod_array << mod_name.register()
end
for each item I want to parse
for each module in mod_array
results[module name] = module.parse(data)
end
end
for each module in array
print module.generate_results (results[module name])
end
A common way of doing this in Go is to have a per file init() that registers the function or type in that file in some package-level variable. I typed up an example for that a while back here on the forum but I can’t find it… Basically
main.go
var registry = make(map[string]func() string)
func main() {
for name, fn := registry {
fmt.Println(name, "says", fn())
}
}
I spent this morning playing with modules and interfaces and came up with a way that worked but required me to do some work when I added a new module, merging that with this I think will do just what I need. Thanks.