Home > Enterprise >  Dart How to load file in runtime
Dart How to load file in runtime

Time:07-16

I'm writing a discord bot using the nyxx library and want use dynamic file import for load command info and handler. But, after 5 hours of searching with Google, I didn't find anything to help me do that.

In Node.js, I can use require() or import() for it: Does the dart have something like that?

A small code snippet, showing what I want do:

this.commands = new Collection();
fs.readdirSync('./src/commands').filter(( f ) => f.endsWith( '.js' )).forEach((file) => {
    const command = require(`../commands/${file}`);
    this.commands.set( command.info.name, command );
});

Is it possible to do this or not? (I don't like to write many imports for commands and register it in lib.)

CodePudding user response:

You can in theory use Isolate.spawnUri to spawn external Dart programs to run in its own Isolate instances that can then communicate back to the main program using SendPort.

It does, however, come with some limitations. E.g. it is very limited what types of objects you can send though SendPort when using spawnUri since the two programs does not share any type information (compared to Isolate.spawn which does allow you to send your own custom types). The documented types you can send can be found here:

  • Null
  • bool
  • int
  • double
  • String
  • List or Map (whose elements are any of these)
  • TransferableTypedData
  • SendPort
  • Capability

https://api.dart.dev/stable/2.17.6/dart-isolate/SendPort/send.html

But it does allow us to make some kind of protocol and you can create some helper class around this to handle the conversion of a known object structure into e.g. Map<String, Object>.

A small example that works with Dart VM would be:

Your command implemented as: command.dart

import 'dart:isolate';

void main(List<String> arguments, Map<String, Object> message) {
  final userName = message['username'] as String;
  final sendPort = message['port'] as SendPort;

  sendPort.send('Hi $userName. '
      'You got a message from my external command program!');
}

Your server that calls your command: server.dart

import 'dart:isolate';

void main() {
  final recievePort = ReceivePort();

  recievePort.listen((message) {
    print('Got the following message: $message');
    recievePort.close();
  });

  Isolate.spawnUri(Uri.file('command.dart'), [], {
    'username': 'julemand101',
    'port': recievePort.sendPort,
  });
}

If running this with: dart server.dart you, hopefully, get:

Got the following message: Hi julemand101. You got a message from my external command program!

If you want to compile your application, you can do so by doing the following. You need to compile the command.dart, since a compiled Dart program does not understand how to read Dart code.

dart compile exe server.dart
dart compile aot-snapshot command.dart

You should here change Uri.file('command.dart') to Uri.file('command.aot') since the file-extension for aot-snapshot are .aot.

If everything works, you should be able to see:

> .\server.exe                
Got the following message: Hi julemand101. You got a message from my external command program!
  •  Tags:  
  • dart
  • Related