<commit_before>package com.tns;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.support.annotation.NonNull;

public class NativeScriptSyncService {
    private static String DEVICE_APP_DIR;

    private final Runtime runtime;
    private static Logger logger;
    private final Context context;

    private LocalServerSocketThread localServerThread;
    private Thread localServerJavaThread;

    public NativeScriptSyncService(Runtime runtime, Logger logger, Context context) {
        this.runtime = runtime;
        this.logger = logger;
        this.context = context;
        DEVICE_APP_DIR = this.context.getFilesDir().getAbsolutePath() + "/app";
    }

    private class LocalServerSocketThread implements Runnable {

        private volatile boolean running;
        private final String name;

        private LiveSyncWorker livesyncWorker;
        private LocalServerSocket deviceSystemSocket;

        public LocalServerSocketThread(String name) {
            this.name = name;
            this.running = false;
        }

        public void stop() {
            this.running = false;
            try {
                deviceSystemSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void run() {
            running = true;
            try {
                deviceSystemSocket = new LocalServerSocket(this.name);
                while (running) {
                    LocalSocket systemSocket = deviceSystemSocket.accept();
                    livesyncWorker = new LiveSyncWorker(systemSocket);
                    Thread livesyncThread = setUpLivesyncThread();
                    livesyncThread.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @NonNull
        private Thread setUpLivesyncThread() {
            Thread livesyncThread = new Thread(livesyncWorker);
            livesyncThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    logger.write(String.format("%s(%s): %s", t.getName(), t.getId(), e.toString()));
                }
            });
            livesyncThread.setName("Livesync Thread");
            return livesyncThread;
        }

        @Override
        protected void finalize() throws Throwable {
            deviceSystemSocket.close();
        }
    }

    public void startServer() {
        localServerThread = new LocalServerSocketThread(context.getPackageName() + "-livesync");
        localServerJavaThread = new Thread(localServerThread);
        localServerJavaThread.start();
    }

    private class LiveSyncWorker implements Runnable {
        public static final int OPERATION_BYTE_SIZE = 1;
        public static final int FILE_NAME_LENGTH_BYTE_SIZE = 5;
        public static final int CONTENT_LENGTH_BYTE_SIZE = 10;
        public static final int DELETE_FILE_OPERATION = 7;
        public static final int CREATE_FILE_OPERATION = 8;
        public static final String FILE_NAME = "fileName";
        public static final String FILE_NAME_LENGTH = FILE_NAME + "Length";
        public static final String OPERATION = "operation";
        public static final String FILE_CONTENT = "fileContent";
        public static final String FILE_CONTENT_LENGTH = FILE_CONTENT + "Length";
        public static final int DEFAULT_OPERATION = -1;
        public final String LIVESYNC_ERROR_SUGGESTION = String.format("\nMake sure you are following this protocol when transferring files." +
                "\nTransfer protocol: \n\tdelete: (%s)(%s)(%s)" +
                "\n\tcreate: (%s)(%s)(%s)(%s)(%s)" +
                "\n\t%s: exactly %s btye (%s - delete, %s - create)" +
                "\n\t%s: exactly %s bytes" +
                "\n\t%s: relative to app folder" +
                "\n\t%s: exactly %s bytes" +
                "\n\t%s: byte buffer" +
                "\n\tExample delete: 700003./a" +
                "\n\tExample create: 800007./a.txt0000000011fileContent",
                OPERATION, FILE_NAME_LENGTH, FILE_NAME,
                OPERATION, FILE_NAME_LENGTH, FILE_NAME, FILE_CONTENT_LENGTH, FILE_CONTENT,
                OPERATION, OPERATION_BYTE_SIZE, DELETE_FILE_OPERATION, CREATE_FILE_OPERATION,
                FILE_NAME_LENGTH, FILE_NAME_LENGTH_BYTE_SIZE,
                FILE_NAME,
                FILE_CONTENT_LENGTH, CONTENT_LENGTH_BYTE_SIZE,
                FILE_CONTENT);
        private final InputStream input;
        private Closeable livesyncSocket;
        private OutputStream output;

        public LiveSyncWorker(LocalSocket systemSocket) throws IOException {
            this.livesyncSocket = systemSocket;
            input = systemSocket.getInputStream();
            output = systemSocket.getOutputStream();
        }

        public void run() {
            try {

                output.write(context.getPackageName().getBytes());

            } catch (IOException e) {
                logger.write(String.format("Error while LiveSyncing: Client socket might be closed!", e.toString()));
                e.printStackTrace();
            }
            try {
                do {
                    int operation = getOperation();

                    System.out.println("Operation: " + input.available());
                    if (operation == DELETE_FILE_OPERATION) {

                        String fileName = getFileName();
                        deleteRecursive(new File(DEVICE_APP_DIR, fileName));

                    } else if (operation == CREATE_FILE_OPERATION) {

                        String fileName = getFileName();
                        byte[] content = getFileContent(fileName);
                        createOrOverrideFile(fileName, content);

                    } else if (operation == DEFAULT_OPERATION) {
                        logger.write("LiveSync: input stream is empty!");
                        break;
                    } else {
                        throw new IllegalArgumentException(String.format("\nLiveSync: Operation not recognised. %s", LIVESYNC_ERROR_SUGGESTION));
                    }

                    //TODO: do debouncing
                    runtime.runScript(new File(NativeScriptSyncService.this.context.getFilesDir(), "internal/livesync.js"));
                } while (true);

            } catch (Exception e) {
                logger.write(String.format("Error while LiveSyncing: %s", e.toString()));
                e.printStackTrace();<commit_msg>feature(livesnc): add dosync operation to avoid debouncing<commit_after>package com.tns;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.support.annotation.NonNull;

public class NativeScriptSyncService {
    private static String DEVICE_APP_DIR;

    private final Runtime runtime;
    private static Logger logger;
    private final Context context;

    private LocalServerSocketThread localServerThread;
    private Thread localServerJavaThread;

    public NativeScriptSyncService(Runtime runtime, Logger logger, Context context) {
        this.runtime = runtime;
        this.logger = logger;
        this.context = context;
        DEVICE_APP_DIR = this.context.getFilesDir().getAbsolutePath() + "/app";
    }

    private class LocalServerSocketThread implements Runnable {

        private volatile boolean running;
        private final String name;

        private LiveSyncWorker livesyncWorker;
        private LocalServerSocket deviceSystemSocket;

        public LocalServerSocketThread(String name) {
            this.name = name;
            this.running = false;
        }

        public void stop() {
            this.running = false;
            try {
                deviceSystemSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void run() {
            running = true;
            try {
                deviceSystemSocket = new LocalServerSocket(this.name);
                while (running) {
                    LocalSocket systemSocket = deviceSystemSocket.accept();
                    livesyncWorker = new LiveSyncWorker(systemSocket);
                    Thread livesyncThread = setUpLivesyncThread();
                    livesyncThread.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @NonNull
        private Thread setUpLivesyncThread() {
            Thread livesyncThread = new Thread(livesyncWorker);
            livesyncThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    logger.write(String.format("%s(%s): %s", t.getName(), t.getId(), e.toString()));
                }
            });
            livesyncThread.setName("Livesync Thread");
            return livesyncThread;
        }

        @Override
        protected void finalize() throws Throwable {
            deviceSystemSocket.close();
        }
    }

    public void startServer() {
        localServerThread = new LocalServerSocketThread(context.getPackageName() + "-livesync");
        localServerJavaThread = new Thread(localServerThread);
        localServerJavaThread.start();
    }

    private class LiveSyncWorker implements Runnable {
        public static final int OPERATION_BYTE_SIZE = 1;
        public static final int FILE_NAME_LENGTH_BYTE_SIZE = 5;
        public static final int CONTENT_LENGTH_BYTE_SIZE = 10;
        public static final int DELETE_FILE_OPERATION = 7;
        public static final int CREATE_FILE_OPERATION = 8;
        public static final int DO_SYNC_OPERATION = 9;
        public static final String FILE_NAME = "fileName";
        public static final String FILE_NAME_LENGTH = FILE_NAME + "Length";
        public static final String OPERATION = "operation";
        public static final String FILE_CONTENT = "fileContent";
        public static final String FILE_CONTENT_LENGTH = FILE_CONTENT + "Length";
        public static final int DEFAULT_OPERATION = -1;
        public final String LIVESYNC_ERROR_SUGGESTION = String.format("\nMake sure you are following this protocol when transferring files." +
                "\nTransfer protocol: \n\tdelete: (%s)(%s)(%s)" +
                "\n\tcreate: (%s)(%s)(%s)(%s)(%s)" +
                "\n\t%s: exactly %s btye (%s - delete, %s - create)" +
                "\n\t%s: exactly %s bytes" +
                "\n\t%s: relative to app folder" +
                "\n\t%s: exactly %s bytes" +
                "\n\t%s: byte buffer" +
                "\n\tExample delete: 700003./a" +
                "\n\tExample create: 800007./a.txt0000000011fileContent",
                OPERATION, FILE_NAME_LENGTH, FILE_NAME,
                OPERATION, FILE_NAME_LENGTH, FILE_NAME, FILE_CONTENT_LENGTH, FILE_CONTENT,
                OPERATION, OPERATION_BYTE_SIZE, DELETE_FILE_OPERATION, CREATE_FILE_OPERATION,
                FILE_NAME_LENGTH, FILE_NAME_LENGTH_BYTE_SIZE,
                FILE_NAME,
                FILE_CONTENT_LENGTH, CONTENT_LENGTH_BYTE_SIZE,
                FILE_CONTENT);
        private final InputStream input;
        private Closeable livesyncSocket;
        private OutputStream output;

        public LiveSyncWorker(LocalSocket systemSocket) throws IOException {
            this.livesyncSocket = systemSocket;
            input = systemSocket.getInputStream();
            output = systemSocket.getOutputStream();
        }

        public void run() {
            try {

                output.write(context.getPackageName().getBytes());

            } catch (IOException e) {
                logger.write(String.format("Error while LiveSyncing: Client socket might be closed!", e.toString()));
                e.printStackTrace();
            }
            try {
                do {
                    int operation = getOperation();

                    if (operation == DELETE_FILE_OPERATION) {

                        String fileName = getFileName();
                        deleteRecursive(new File(DEVICE_APP_DIR, fileName));

                    } else if (operation == CREATE_FILE_OPERATION) {

                        String fileName = getFileName();
                        byte[] content = getFileContent(fileName);
                        createOrOverrideFile(fileName, content);

                    } else if (operation == DO_SYNC_OPERATION) {

                        runtime.runScript(new File(NativeScriptSyncService.this.context.getFilesDir(), "internal/livesync.js"));

                    } else if (operation == DEFAULT_OPERATION) {
                        logger.write("LiveSync: input stream is empty!");
                        break;
                    } else {
                        throw new IllegalArgumentException(String.format("\nLiveSync: Operation not recognised. %s", LIVESYNC_ERROR_SUGGESTION));
                    }

                } while (true);

            } catch (Exception e) {
                logger.write(String.format("Error while LiveSyncing: %s", e.toString()));
                e.printStackTrace();
{'fraction_non_alphanumeric': 0.08577253531381972, 'fraction_numerical': 0.004295907965632736, 'mean_word_length': 1.9761646803900326, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7391388', 'n_tokens_mistral': 3512, 'n_tokens_neox': 3307, 'n_words': 836}