Scripter is an extension that introduces scripting support to PETEP.

Scripting is based on GraalVM Polyglot, which support JavaScript language out-of-the-box. One of the greatest advantages is that you can use Java libraries in the code, so you can also use PETEP utils etc.

Note: If you edit a File script, you have to reload the script in the PETEP UI.

Note: All scripts are persisted in Groups. You have to define these groups and bind them with specific Scripter interceptors to make them work.

## Scripter interfaces

Scripter currently has the following interface accessible through "scripter" variable:

void registerInterceptor(ScriptInterceptor interceptor)
  Registers interceptor that allows you to work with PDUs.
void require(String path)
  Loads script from specified path.
ScriptLogger getLogger()
  Returns simplified logger.
ExtensionHelper getExtensionHelper()
  Returns extension helper (see DEV guide).

### Script interceptor

boolean intercept(PDU pdu, PetepHelper helper)
  This method is called automatically for each PDU that goes through the interceptor.

### Script logger

void info(String message)
  Extension should be initalized inside this method - registration of modules etc.
void warning(String message)
  Extension GUI should be initialized inside this method - creation of tabs etc.
void error(String message)
  Extension GUI should be initialized inside this method - creation of tabs etc.

## Pro Tip

Use PETEP's Java utils to work with the PDUs. This can be achieved using the Java.type function:

    const PduUtils = Java.type('com.warxim.petep.util.PduUtils');
    const BytesUtils = Java.type('com.warxim.petep.util.BytesUtils');

Take full advantage of Java interoperability, see GraalVM Java Interoperability

## Special tags

In order to specify, which PDUs should be processed using scripts, you can tag them using the following tags (all PDUs are processed by default):

- no_scripter - tagged PDU won't be processed
- scripter - tagged PDU will be processed even if it already has no_scripter tag.

## Example scripts

The following examples are part of Example preset. There are three scripts - simple replacer, logging interceptor and colorizing interceptor.

### Simple console replacer - custom

This simple script uses JavaScript to process custom replacement. (Replaces bytes at specific index with given data.)

#### replacer.js

    // Imports
    const BytesUtils = Java.type('com.warxim.petep.util.BytesUtils');

    // Config
    const NEW_DATA = BytesUtils.hexStringToBytes('3A 29');
    const TARGET_INDEX = 2;
    const TARGET_LENGTH = NEW_DATA.length;
    const TARGET_TAG = 'tag-1';

    // Replacer
    scripter.registerInterceptor({
        intercept: function(pdu, helper) {
            const buffer = pdu.getBuffer();

            if (!pdu.hasTag(TARGET_TAG)) {
                return true;
            }

            for (let i = 0; i < TARGET_LENGTH; ++i) {
                buffer[TARGET_INDEX + i] = NEW_DATA[i];
            }

            return true;
        }
    });

### Simple console logger

This simple script uses logger and PduUtils to print information about PDUs to console.

#### log-config.js

    var config = {};

    config.messages = {
    	init: 'Script initialized!'
    };

    config.log = {
    	type: true,
    	size: true,
    	proxy: true,
    	connection: true,
    	interceptor: false,
    	destination: true,
    	tags: true,
    	buffer: false
    };

#### logger.js

    // Import config script
    scripter.require('log-config.js');

    // Load PETEP utils
    const PduUtils = Java.type('com.warxim.petep.util.PduUtils');

    // Load Java utils
    const StringJoiner = Java.type('java.util.StringJoiner');
    const ArrayList = Java.type('java.util.ArrayList');

    // Obtain logger
    const log = scripter.getLogger();
    log.info(config.messages.init);

    // Register info interceptor
    scripter.registerInterceptor({
        intercept: function(pdu, helper) {
    		var information = '';

    		if (config.log.type) {
    			information += '\n- type: ' + pdu.getClass().getSimpleName();
    		}

    		if (config.log.destination) {
    			information += '\n- destination: ' + pdu.getDestination();
    		}

    		if (config.log.proxy) {
    			let proxy = pdu.getProxy();
    			information += '\n- proxy: ' + proxy.getName() + ' (' + proxy.getCode() + ')';
    		}

    		if (config.log.connection) {
    			let connection = pdu.getConnection();
    			information += '\n- connection: ' + connection.getCode();
    		}

    		if (config.log.interceptor) {
    			let interceptor = pdu.getLastInterceptor();
    			information += '\n- last interceptor: ' + interceptor.getName() + ' (' + interceptor.getCode() + ')';
    		}

    		if (config.log.size) {
    			information += '\n- size: ' + pdu.getSize();
    		}

    		if (config.log.tags) {
    			let tagJoiner = new StringJoiner(', ');
    			pdu.getTags().forEach(tagJoiner.add);
    			information += '\n- tags: ' + tagJoiner.toString();
    		}

    		if (config.log.buffer) {
    			information += '\n- buffer: ' + PduUtils.bufferToHexString(pdu);
    		}

    		if (information.length > 0) {
    			log.info('PDU information: ' + information);
    		}

    		return true;
    	}
    });

### Simple console replacer - using internal utils

This simple script uses PduUtils and BytesUtils to replace colors in the PDU data.

#### color-config.js

    var config = {};

    config.colors = {
    	'#383b53': '#533838',
    	'#b4b9e6': '#e6b4b4',
    	'#8e96d9': '#d98e8e',
    	'#33364b': '#4b3333',
    	'#1f2639': '#391f1f',
    	'#403e66': '#663e3e',
    	'#daddf3': '#f3dada',
    	'#edeff9': '#f9eded',
    	'#f9f9fd': '#fdf9f9',
    	'#f7f8fc': '#fcf7f7',
    	'rgba(142,150,217,0.25)': 'rgba(217,142,142,0.25)'
    }

#### colorizer.js

    // Import config script
    scripter.require('color-config.js');

    // Load PETEP utils
    const PduUtils = Java.type('com.warxim.petep.util.PduUtils');
    const BytesUtils = Java.type('com.warxim.petep.util.BytesUtils');

    // Register colorize interceptor
    scripter.registerInterceptor({
        intercept: function(pdu, helper) {
    		if (pdu.getProxy().getCode() !== 'petep') {
    			return true;
    		}

    		for (let currentColor in config.colors) {
    			let newColor = config.colors[currentColor];
    			PduUtils.replace(
    				pdu,
    				BytesUtils.getBytes(currentColor),
    				BytesUtils.getBytes(newColor)
    			);
    		}
    		return true;
        }
    });