Language Implementation Guide - UltimatePea/UniversalLanguageInterface GitHub Wiki

This documentation is intended to be used as a guide to instruct the implementation of this Interface in different programming languages. Please refer to language specific guide if you want to use this interface.

The function that can be called must take a single string as argument and return a single string as result. It is up to the specific implementer on how the strings are encoded and decoded. It is recommended to use encodings like JSON pass complex data structure.

Calling Introduction

All calls are blocking for now. Async calls might be added in the future.

Calls are made via command line with three command line arguments.

  • --mode -- either single, stream. I will probably implement single only as of 0.x ~ 1.0 release. I will bring stream in 2.x. I plan to add server which accepts incoming function calls via network in 3.x versions.

  • --input-pipe -- the file path for caller -> callee unix named pipe.

  • --output-pipe -- the file path for callee -> caller unix named pipe.

Callee Responsibility

Callee will read input-pipe for one line only. This line contains string in JSON format for the function the the caller intended to call. The JSON will look like the following

{
    "name": "FUNCTION_NAME",
    "args": "ARG_VALUE"
             
}

The callee will then call the function denoted by FUNCTION_NAME with the argument list, and write to output-pipe one line in the following JSON format.

{
     "code":200,
     "return_val":"RETURN_VAL_IN_STRING"
}

Note that all values (arguments, return value, function names) are strings.

If an error occurred during the calling, the callee should try its best not to crash the program but instead write the following JSON to output-pipe.

{
      "code":500,
      "message":"ERROR_REASON"
}

Caller Responsibility

The caller is responsible for creating subprocess and necessary pipes.

Calling mode. Caller is handles calling mode differently for different programming languages. For compiled binary languages, caller will specify a single program name, e.g. (someprog/a.out). For interpreted language, caller can accept interpreter name, e.g. (python3) and a program file name, e.g. (uli_exposed.py).

Due to the nature of blocking of opening FIFOs on unix, the procedure must be followed exactly to avoid stuck.

Steps:

  1. Caller Construct temporary FIFOs.

The recommended practice is to create a temporary directory under system temporary directory. Then use mkfifo to create two fifos, inp for caller -> callee communication and outp for callee -> caller communication.

Please make sure security is handled properly here. Document any insecure operations using TODO.

  1. Caller create and start a another process.

The starting process should be non blocking, to allow open files for constructed fifos.

  1. Caller opens inp in WriteMode and write one line:
{
    "name": "FUNCTION_NAME",
    "args": "ARG_VALUE"
}
  1. Caller opens outp in ReadMode

  2. Caller join to wait for the subprocess to finish.

  3. Caller read one line from outp and parse the output

  4. Caller check response code and make necessary actions.

  5. Caller delete the temporary FIFO (inp, outp) and the temporary directory.

  6. Caller returns the resulting object to the host program.

It is important to remove temporary directory for cleaning up

Note: the child process will stuck until both input and output pipes are open