Package org.perl6.nqp.io

Source Code of org.perl6.nqp.io.AsyncSocketHandle$Decoder

package org.perl6.nqp.io;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;

import org.perl6.nqp.runtime.Buffers;
import org.perl6.nqp.runtime.ExceptionHandling;
import org.perl6.nqp.runtime.HLLConfig;
import org.perl6.nqp.runtime.Ops;
import org.perl6.nqp.runtime.ThreadContext;
import org.perl6.nqp.sixmodel.SixModelObject;
import org.perl6.nqp.sixmodel.reprs.AsyncTaskInstance;
import org.perl6.nqp.sixmodel.reprs.ConcBlockingQueueInstance;
import org.perl6.nqp.sixmodel.reprs.IOHandleInstance;

public class AsyncSocketHandle implements IIOClosable, IIOEncodable {

    private AsynchronousSocketChannel channel;

    private CharsetEncoder enc;
    private CharsetDecoder dec;

    public AsyncSocketHandle(ThreadContext tc) {
        try {
            this.channel = AsynchronousSocketChannel.open();
            setEncoding(tc, Charset.forName("UTF-8"));
        } catch (IOException e) {
            throw ExceptionHandling.dieInternal(tc, e);
        }
    }

    public AsyncSocketHandle(ThreadContext tc, AsynchronousSocketChannel channel) {
        this.channel = channel;
        setEncoding(tc, Charset.forName("UTF-8"));
    }

    public void connect(final ThreadContext tc, String host, int port,
            final AsyncTaskInstance task) {

        final CompletionHandler<Void, AsyncTaskInstance> handler
            = new CompletionHandler<Void, AsyncTaskInstance>() {

            HLLConfig hllConfig = tc.curFrame.codeRef.staticInfo.compUnit.hllConfig;
            final SixModelObject IOType = hllConfig.ioType;
            final SixModelObject Array = hllConfig.listType;
            final SixModelObject Str = hllConfig.strBoxType;

            @Override
            public void completed(Void v, AsyncTaskInstance task) {
                ThreadContext curTC = tc.gc.getCurrentThreadContext();

                IOHandleInstance ioHandle = (IOHandleInstance) IOType.st.REPR.allocate(curTC,
                        IOType.st);
                ioHandle.handle = task.handle;
                callback(curTC, task, ioHandle, Str);
            }

            @Override
            public void failed(Throwable t, AsyncTaskInstance task) {
                ThreadContext curTC = tc.gc.getCurrentThreadContext();
                callback(curTC, task, IOType, Ops.box_s(t.toString(), Str, curTC));
            }

            protected void callback(ThreadContext tc, AsyncTaskInstance task, SixModelObject ioHandle, SixModelObject err) {
                SixModelObject result = Array.st.REPR.allocate(tc, Array.st);
                result.push_boxed(tc, task.schedulee);
                result.push_boxed(tc, ioHandle);
                result.push_boxed(tc, err);
                ((ConcBlockingQueueInstance) task.queue).push_boxed(tc, result);
            }
        };

        try {
            InetSocketAddress addr = new InetSocketAddress(host, port);
            channel.connect(addr, task, handler);
        } catch (Throwable e) {
            throw ExceptionHandling.dieInternal(tc, e);
        }
    }

    public void writeStr(ThreadContext tc, AsyncTaskInstance task, String toWrite) {
        try {
            ByteBuffer buffer = enc.encode(CharBuffer.wrap(toWrite));
            writeByteBuffer(tc, task, buffer);
        } catch (Throwable e) {
            throw ExceptionHandling.dieInternal(tc, e);
        }
    }

    public void writeBytes(ThreadContext tc, AsyncTaskInstance task, SixModelObject toWrite) {
        ByteBuffer buffer = Buffers.unstashBytes(toWrite, tc);
        writeByteBuffer(tc, task, buffer);
    }

    private void writeByteBuffer(final ThreadContext tc, final AsyncTaskInstance task, ByteBuffer buffer) {
        try {
            HLLConfig hllConfig = tc.curFrame.codeRef.staticInfo.compUnit.hllConfig;
            final SixModelObject Array = hllConfig.listType;
            final SixModelObject Int = hllConfig.intBoxType;
            final SixModelObject Null = hllConfig.nullValue;
            final SixModelObject Str = hllConfig.strBoxType;

            CompletionHandler<Integer, AsyncTaskInstance> handler
                = new CompletionHandler<Integer, AsyncTaskInstance>() {

                @Override
                public void completed(Integer bytesWritten, AsyncTaskInstance task) {
                    ThreadContext curTC = tc.gc.getCurrentThreadContext();
                    callback(curTC, task, Ops.box_i(bytesWritten, Int, curTC), Null);
                }

                @Override
                public void failed(Throwable t, AsyncTaskInstance attachment) {
                    ThreadContext curTC = tc.gc.getCurrentThreadContext();
                    callback(curTC, task, Str, Ops.box_s(t.toString(), Str, curTC));
                }

                protected void callback(ThreadContext tc, AsyncTaskInstance task, SixModelObject bytesWritten, SixModelObject err) {
                    SixModelObject result = Array.st.REPR.allocate(tc, Array.st);
                    result.push_boxed(tc, task.schedulee);
                    result.push_boxed(tc, bytesWritten);
                    result.push_boxed(tc, err);
                    ((ConcBlockingQueueInstance) task.queue).push_boxed(tc, result);
                }
            };

            channel.write(buffer, task, handler);
        } catch (Throwable e) {
            throw ExceptionHandling.dieInternal(tc, e);
        }
    }

    public void readChars(final ThreadContext tc, final AsyncTaskInstance task) {
        HLLConfig hllConfig = tc.curFrame.codeRef.staticInfo.compUnit.hllConfig;
        final SixModelObject Str = hllConfig.strBoxType;

        readSocket(tc, task, new Decoder () {
            final CharBuffer decodedBuffer = CharBuffer.allocate(32768);

            public SixModelObject decode(ThreadContext tc, ByteBuffer source, Integer numRead) throws Exception {
                CoderResult coderResult = dec.decode(source, decodedBuffer, numRead == 0 ? true : false);
                if (coderResult.isError()) {
                    coderResult.throwException();
                }
                decodedBuffer.flip();
                String decoded = decodedBuffer.toString();
                decodedBuffer.clear();
                return Ops.box_s(decoded, Str, tc);
            }
        });
    }

    public void readBytes(final ThreadContext tc, final AsyncTaskInstance task, final SixModelObject bufType) {
        readSocket(tc, task, new Decoder() {
            public SixModelObject decode(ThreadContext tc, ByteBuffer source, Integer numRead)
                    throws Exception {
                SixModelObject res = bufType.st.REPR.allocate(tc, bufType.st);
                byte[] bytes = new byte[source.remaining()];
                source.get(bytes);
                Buffers.stashBytes(tc, res, bytes);
                return res;
            }
        });
    }

    static interface Decoder {
        public SixModelObject decode(ThreadContext tc, ByteBuffer source, Integer numRead) throws Exception;
    }

    private void readSocket(final ThreadContext tc, final AsyncTaskInstance task, final Decoder decoder) {
        final ByteBuffer readBuffer = ByteBuffer.allocate(32768);

        HLLConfig hllConfig = tc.curFrame.codeRef.staticInfo.compUnit.hllConfig;
        final SixModelObject Array = hllConfig.listType;
        final SixModelObject Int = hllConfig.intBoxType;
        final SixModelObject Str = hllConfig.strBoxType;
        final SixModelObject Null = hllConfig.nullValue;

        CompletionHandler<Integer, AsyncTaskInstance> handler
        = new CompletionHandler<Integer, AsyncTaskInstance>() {

            @Override
            public void completed(Integer numRead, AsyncTaskInstance task) {
                ThreadContext curTC = tc.gc.getCurrentThreadContext();

                try {
                    if (numRead == -1) {
                        task.seq = -1;
                        callback(curTC, task, -1, Str, Null);
                    } else {
                        readBuffer.flip();
                        SixModelObject decoded = decoder.decode(tc, readBuffer, numRead);
                        readBuffer.compact();

                        callback(curTC, task, task.seq++, decoded, Null);

                        channel.read(readBuffer, task, this);
                    }
                } catch (Throwable t) {
                    failed(t, task);
                }
            }

            @Override
            public void failed(Throwable t, AsyncTaskInstance task) {
                ThreadContext curTC = tc.gc.getCurrentThreadContext();
                SixModelObject err = (t instanceof AsynchronousCloseException)
                        ? Str : Ops.box_s(t.toString(), Str, curTC);
                callback(curTC, task, -1, Str, err);
            }

            protected void callback(ThreadContext tc, AsyncTaskInstance task, long seq, SixModelObject str, SixModelObject err) {
                SixModelObject result = Array.st.REPR.allocate(tc, Array.st);
                result.push_boxed(tc, task.schedulee);
                result.push_boxed(tc, Ops.box_i(seq, Int, tc));
                result.push_boxed(tc, str);
                result.push_boxed(tc, err);
                ((ConcBlockingQueueInstance) task.queue).push_boxed(tc, result);
            }
        };

        try {
            channel.read(readBuffer, task, handler);
        } catch (Throwable t) {
            handler.failed(t, task);
        }
    }

    @Override
    public void close(ThreadContext tc) {
        try {
            channel.close();
        } catch (IOException e) {
            throw ExceptionHandling.dieInternal(tc, e);
        }
    }

    @Override
    public void setEncoding(ThreadContext tc, Charset cs) {
        enc = cs.newEncoder();
        dec = cs.newDecoder();
    }
}
TOP

Related Classes of org.perl6.nqp.io.AsyncSocketHandle$Decoder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.