All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.koushikdutta.async.Util Maven / Gradle / Ivy

Go to download

Asynchronous socket, http(s) (client+server) and websocket library for android. Based on nio, not threads.

There is a newer version: 3.1.0
Show newest version
package com.koushikdutta.async;

import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.callback.DataCallback;
import com.koushikdutta.async.callback.WritableCallback;
import com.koushikdutta.async.wrapper.AsyncSocketWrapper;
import com.koushikdutta.async.wrapper.DataEmitterWrapper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

public class Util {
    public static void emitAllData(DataEmitter emitter, ByteBufferList list) {
        int remaining;
        DataCallback handler = null;
        while (!emitter.isPaused() && (handler = emitter.getDataCallback()) != null && (remaining = list.remaining()) > 0) {
            handler.onDataAvailable(emitter, list);
            if (remaining == list.remaining() && handler == emitter.getDataCallback() && !emitter.isPaused()) {
                // this is generally indicative of failure...

                // 1) The data callback has not changed
                // 2) no data was consumed
                // 3) the data emitter was not paused

                // call byteBufferList.recycle() or read all the data to prevent this assertion.
                // this is nice to have, as it identifies protocol or parsing errors.

//                System.out.println("Data: " + list.peekString());
                System.out.println("handler: " + handler);
                assert false;
                throw new RuntimeException("mDataHandler failed to consume data, yet remains the mDataHandler.");
            }
        }
        if (list.remaining() != 0 && !emitter.isPaused()) {
            // not all the data was consumed...
            // call byteBufferList.recycle() or read all the data to prevent this assertion.
            // this is nice to have, as it identifies protocol or parsing errors.
//            System.out.println("Data: " + list.peekString());
            System.out.println("handler: " + handler);
            System.out.println("emitter: " + emitter);
            assert false;
            throw new RuntimeException("Not all data was consumed by Util.emitAllData");
        }
    }

    public static void pump(final InputStream is, final DataSink ds, final CompletedCallback callback) {
        pump(is, Integer.MAX_VALUE, ds, callback);
    }

    public static void pump(final InputStream is, final long max, final DataSink ds, final CompletedCallback callback) {
        final CompletedCallback wrapper = new CompletedCallback() {
            boolean reported;
            @Override
            public void onCompleted(Exception ex) {
                if (reported)
                    return;
                reported = true;
                callback.onCompleted(ex);
            }
        };

        final WritableCallback cb = new WritableCallback() {
            int totalRead = 0;
            private void cleanup() {
                ds.setClosedCallback(null);
                ds.setWriteableCallback(null);
                ByteBufferList.reclaim(pending);
                pending = null;
                try {
                    is.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            ByteBuffer pending;
            int mToAlloc = 0;
            int maxAlloc = 256 * 1024;

            @Override
            public void onWriteable() {
                try {
                    do {
                        if (pending == null || pending.remaining() == 0) {
                            ByteBufferList.reclaim(pending);
                            pending = ByteBufferList.obtain(Math.min(Math.max(mToAlloc, 2 << 11), maxAlloc));

                            long toRead = Math.min(max - totalRead, pending.capacity());
                            int read = is.read(pending.array(), 0, (int)toRead);
                            if (read == -1 || totalRead == max) {
                                cleanup();
                                wrapper.onCompleted(null);
                                return;
                            }
                            mToAlloc = read * 2;
                            totalRead += read;
                            pending.position(0);
                            pending.limit(read);
                        }
                        
                        ds.write(pending);
                    }
                    while (!pending.hasRemaining());
                }
                catch (Exception e) {
                    cleanup();
                    wrapper.onCompleted(e);
                }
            }
        };
        ds.setWriteableCallback(cb);

        ds.setClosedCallback(wrapper);
        
        cb.onWriteable();
    }
    
    public static void pump(final DataEmitter emitter, final DataSink sink, final CompletedCallback callback) {
        final DataCallback dataCallback = new DataCallback() {
            @Override
            public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
                sink.write(bb);
                if (bb.remaining() > 0)
                    emitter.pause();
            }
        };
        emitter.setDataCallback(dataCallback);
        sink.setWriteableCallback(new WritableCallback() {
            @Override
            public void onWriteable() {
                dataCallback.onDataAvailable(emitter, new ByteBufferList());
                emitter.resume();
            }
        });

        CompletedCallback wrapper = new CompletedCallback() {
            boolean reported;
            @Override
            public void onCompleted(Exception ex) {
                if (reported)
                    return;
                emitter.setEndCallback(null);
                sink.setClosedCallback(null);
                sink.setWriteableCallback(null);
                reported = true;
                callback.onCompleted(ex);
            }
        };

        emitter.setEndCallback(wrapper);
        sink.setClosedCallback(wrapper);
    }
    
    public static void stream(AsyncSocket s1, AsyncSocket s2, CompletedCallback callback) {
        pump(s1, s2, callback);
        pump(s2, s1, callback);
    }
    
    public static void pump(final File file, final DataSink ds, final CompletedCallback callback) {
        try {
            if (file == null || ds == null) {
                callback.onCompleted(null);
                return;
            }
            final InputStream is = new FileInputStream(file);
            pump(is, ds, new CompletedCallback() {
                @Override
                public void onCompleted(Exception ex) {
                    try {
                        is.close();
                        callback.onCompleted(ex);
                    }
                    catch (IOException e) {
                        callback.onCompleted(e);
                    }
                }
            });
        }
        catch (Exception e) {
            callback.onCompleted(e);
        }
    }

    public static void writeAll(final DataSink sink, final ByteBufferList bb, final CompletedCallback callback) {
        WritableCallback wc;
        sink.setWriteableCallback(wc = new WritableCallback() {
            @Override
            public void onWriteable() {
                sink.write(bb);
                if (bb.remaining() == 0 && callback != null) {
                    sink.setWriteableCallback(null);
                    callback.onCompleted(null);
                }
            }
        });
        wc.onWriteable();
    }
    public static void writeAll(DataSink sink, byte[] bytes, CompletedCallback callback) {
        ByteBuffer bb = ByteBufferList.obtain(bytes.length);
        bb.put(bytes);
        bb.flip();
        ByteBufferList bbl = new ByteBufferList();
        bbl.add(bb);
        writeAll(sink, bbl, callback);
    }

    public static  T getWrappedSocket(AsyncSocket socket, Class wrappedClass) {
        if (wrappedClass.isInstance(socket))
            return (T)socket;
        while (socket instanceof AsyncSocketWrapper) {
            socket = ((AsyncSocketWrapper)socket).getSocket();
            if (wrappedClass.isInstance(socket))
                return (T)socket;
        }
        return null;
    }

    public static DataEmitter getWrappedDataEmitter(DataEmitter emitter, Class wrappedClass) {
        if (wrappedClass.isInstance(emitter))
            return emitter;
        while (emitter instanceof DataEmitterWrapper) {
            emitter = ((AsyncSocketWrapper)emitter).getSocket();
            if (wrappedClass.isInstance(emitter))
                return emitter;
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy