Skip to content
woegster edited this page Jan 22, 2017 · 4 revisions

Calling the library

As with any library that has a pure C interface, two methos exist

  • Link against libESRI, static or dynamic when building the host app
  • Load the dynamic library during runtime, find the functions and call them

libESRI

Instances

An instance represents libESRI and there can be multiple instances per application.

  • Create an instance with EsriCreateInstance() - it returns a void*
  • Set the callbacks, see Callbacks
  • Run an Instance with EsriStartInstance(pointerToInstance, port, maxConnections)
  • When finished, release the instance with EsriDeleteInstance(pointerToInstance)

Callbacks

Callbacks are used to communicate with the application.
All callbacks are optional, meaning that a nullptr can be passed instead of a function.

Callback when also provides should return
OnProvideWelcomeMessage first and once on new client string for the welcome text
OnGetCurrentDirectory once after a client connects string for the prompt text
OnProvideCommands once after a client connects string to autocomplete commands
OnCommitCommand enter is pressed string of the entire commandline
OnAbortCommand CTRl-C is pressed
OnExit a client disconnects

All callbacks provide at least two parameter

  • void* handler to identify which client is meant
  • void* userData specified by the application

Callbacks are set with EsriSetHandlersForInstance() BEFORE EsriStartInstance()

Autcomplete

Thanks to ntshell, libESRI can provide autocomplete with TAB for telnet clients.
libESRI will call OnProvideCommands() to get all commands it should 'know' for autocompletition.
This is a ';' seperated string of all commands.
For example: The application can close and open, then the string would be close;open
See the Limitations section

Sync Commands

When OnCommitCommand is called, call EsriPromptTerminal() inside the callback.

OnCommitCommand():
  doWork();
  EsriPromptTerminal();
  return;

Async command

When OnCommitCommand is called, do not call EsriPromptTerminal()
This enters command mode of the terminal, where all input is ignored.
When the async task is finished, call EsriPromptTerminal() to re-enable the terminal

OnCommitCommand(void* client):
  new thread(doWorkInThread(client));
  return;

doWorkInThread(void* client):
  DoWork();
  EsriPromptTerminal(client);

Be aware that when OnExit() is called for the void* client, the handle will no longer be valid!

When CTRL-C is pressed, the application recevies fnHandlerOnAbortCommand()
Cancel the async work and call EsriPromptTerminal() once it has been fully canceled.

##Internal Commands libESRI also provides built-in internal commands.
Internal commands have priority over application commands.
This means that an application can not use these command names:

  • memstat

Multiple async commands

Is a logical combination: start an async worker but call EsriPromptTerminal() anyway.
With the terminal re-enabled, the user can start more async commands.
Make sure that the calls to EsriSendToTerminal() and are synchronized on the application side since they are not in libESRI.

Communicating with the client

Sending text to the client is done by calling EsriSendToTerminal(void* client, string text)
This should be done when the terminal is disable, which is between OnCommitCommand() and a call to EsriPromptTerminal()

Linebreaks in strings

libESRI inserts linebreak in the welcome message and after every commit command.
This is so that an application using it does not have to add "\r\n" into it's strings.
But for multiple output lines created by complex commands, "\r\n" can of course still be used.
Beware that it's still telnet and that \n won't reset to the beginning of the line and that \r\n is needed

Multithreading

Upon calling EsriStartInstance() a new thread is created to listen to the given tcp port.
For every client that connects, a new port is opened.
This means that callbacks can be called concurrently from different clients.
Locking may be needed when the application does not support that.

Thread safety

The application must fullfill the following promises

  • the same instance must not be modified by multiple threads in parallel
  • EsriSendToTerminal on the same handler must not be called by different threads in parallel
  • EsriPromptTerminal on the same handler must not be called by different threads in parallel
  • On the same handler, EsriSendToTerminal an EsriPromptTerminalmust not be called by different threads in parallel

Exiting gracefully

Calling EsriDeleteInstance() will shutdown all clients gracefully.
It will also join all client threads.

Winsock

EsriCreateInstance() will call WSAStartup()
EsriDeleteInstance() will call WSACleanup()
This should work since these calls are reference counted.
Meaning: Deleting an instance of ESRI should not unload Winsock from the host application when it's loaded somewhere else.

Limitations

What Limit defined by in file
line length in telnet 64 NTCONF_EDITOR_MAXLEN 3rdparty/ntshell/ntconf.h
telnet command history 8 NTCONF_HISTORY_DEPTH 3rdparty/ntshell/ntconf.h
autocomplete entires 8 TEXTCOMPLE_MAXENTRIES 3rdparty/ntshell/text_complete.h
length of one autocomplete command 32 TEXTCOMPLETE_MAXLEN 3rdparty/ntshell/text_complete.h