view tango/tango/net/cluster/tina/ProtocolReader.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
line wrap: on
line source

/*******************************************************************************

        copyright:      Copyright (c) 2004 Kris Bell. All rights reserved

        license:        BSD style: $(LICENSE)
        
        version:        July 2004: Initial release      
        
        author:         Kris

*******************************************************************************/

module tango.net.cluster.tina.ProtocolReader;

private import  tango.io.protocol.Reader,
                tango.io.protocol.Allocator,
                tango.io.protocol.PickleProtocol;

private import  tango.net.cluster.model.IMessage;

private import  tango.net.cluster.NetworkRegistry;

private import  tango.net.cluster.tina.ClusterTypes;

/*******************************************************************************
        
        Objects passed around a cluster are prefixed with a header, so the 
        receiver can pick them apart correctly. This header consists of:
        ---
                * the packet size, including the header (16 bits)
                * a command code (8 bits)
                * a version id (8 bits)
                * a timestamp (64 bits)
                * length of the channel name (32 bits)
                * the channel name
                * length of the key (32 bits)
                * the key
                * an optional payload (an IMessage instance)
        ---

        Everything is written in Network order (big endian).

*******************************************************************************/

class ProtocolReader : Reader
{
        /***********************************************************************
        
                Construct a ProtocolReader upon the given buffer. As
                Objects are serialized their content is written to this
                buffer. The buffer content is then typically flushed to 
                some external conduit, such as a file or socket.

                Note that arrays (such as text) are *always* sliced from
                the buffer -- there's no heap activity involved. Thus it
                may be necessary to .dup content where appropriate

        ***********************************************************************/
        
        this (IBuffer buffer)
        {
                super (new BufferSlice (new PickleProtocol (buffer)));
        }

        /***********************************************************************

                deserialize a payload into a provided host, or via
                the registered instance of the incoming payload
                        
        ***********************************************************************/

        IMessage thaw (IMessage host = null)
        {
                return thaw (NetworkRegistry.shared, host);                
        }

        /***********************************************************************

                deserialize a payload into a provided host, or via
                the registered instance of the incoming payload
                        
        ***********************************************************************/

        IMessage thaw (NetworkRegistry registry, IMessage host = null)
        {
                return registry.thaw (this, host);                
        }

        /***********************************************************************
        
                Read the protocol header and return true if there's a 
                payload available

        ***********************************************************************/

        bool getHeader (inout ubyte cmd, inout char[] channel, inout char[] element)
        {
                auto position = buffer.position;

                long   time;
                ushort size;
                ubyte  versn;

                get (size) (cmd) (versn) (time);

                // avoid allocation for these two strings
                get (channel) (element);

                // is there a payload attached?
                if (size > (buffer.position - position))
                    return true;

                return false;
        }

        /***********************************************************************
        
                Return an aliased slice of the buffer representing the 
                recieved payload. This is a bit of a hack, but eliminates
                a reasonable amount of overhead. Note that the channel/key
                text is retained right at the start of the returned content, 
                enabling the host to toss the whole thing back without any 
                further munging. 

        ***********************************************************************/

        ClusterContent getPacket (inout ubyte cmd, inout char[] channel, inout char[] element, inout long time)
        {
                ushort  size;
                ubyte   versn;

                // load up the header
                get (size) (cmd) (versn) (time);

                //printf ("size: %d\n", cast(int) size);

                // subtract header size
                size -= buffer.position;
                
                // may throw an exception if the payload is too large to fit
                // completely inside the buffer!
                buffer.slice (size, false);

                // slice the remaining packet (with channel/key text)
                auto content = cast(ClusterContent) buffer.slice;

                // get a slice upon the channel name
                get (channel);

                // get a slice upon the element name
                get (element);

                // return the aliased payload (including channel/key text)
                return content;
        }
}