1#!/usr/bin/env python
2# encoding: utf8
3#
4# Copyright © Burak Arslan <burak at arskom dot com dot tr>,
5#             Arskom Ltd. http://www.arskom.com.tr
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11#    1. Redistributions of source code must retain the above copyright notice,
12#       this list of conditions and the following disclaimer.
13#    2. Redistributions in binary form must reproduce the above copyright
14#       notice, this list of conditions and the following disclaimer in the
15#       documentation and/or other materials provided with the distribution.
16#    3. Neither the name of the owner nor the names of its contributors may be
17#       used to endorse or promote products derived from this software without
18#       specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
24# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30#
31
32"""
33Raw socket client example for MessagePackDocument via MessagePack server.
34"""
35
36from __future__ import print_function, absolute_import
37
38# These are analogues from spyne.server.msgpack. What's IN_REQUEST there is
39# OUT_REQUEST here because an outgoing request from a client's perspective is an
40# incoming request from a server's perspective.
41IN_RESPONSE_NO_ERROR = 0
42IN_RESPONSE_CLIENT_ERROR = 1
43IN_RESPONSE_SERVER_ERROR = 2
44
45OUT_REQUEST = 1
46
47
48import socket
49import msgpack
50
51from spyne.util.six import BytesIO
52
53s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
54s.connect(("localhost", 5550))
55
56request_document = {"say_hello": ["Dave", 5]}
57
58# Because the server's input protocol is MessagePackDocument, we serialize the
59# request document to msgpack bytestream.
60request_bytestream = msgpack.packb(request_document)
61
62# Because our server side transport is msgpack, we put the request bytestream
63# inside another MessagePack document.
64request_wrapper_document = [OUT_REQUEST, request_bytestream]
65
66# and we serialize the request wrapper document to msgpack bytestream as well
67request_wrapper_bytestream = msgpack.packb(request_wrapper_document)
68
69# Some numbers to show how efficient this is:
70print("Raw message length:", len(request_bytestream))
71print("Wrapped message length:", len(request_wrapper_bytestream))
72print("Overhead:", len(request_wrapper_bytestream) - len(request_bytestream),
73      "byte(s).")
74
75# which we push to the socket.
76s.sendall(request_wrapper_bytestream)
77
78# This is straight from Python example in msgpack.org
79in_buffer = msgpack.Unpacker()
80
81while True:
82    # We wait for the full message to arrive.
83    in_buffer.feed(s.recv(1))
84
85    # Again, straight from the Python example in MessagePack homepage.
86    for msg in in_buffer:
87        print("Raw response document:", msg)
88
89        # There should be only one entry in the response dict. We ignore the
90        # rest here but we could whine about invalid response just as well.
91        resp_code, data = iter(msg.items()).next()
92
93        # We finally parse the response. We should probably do a dict lookup
94        # here.
95        if resp_code == IN_RESPONSE_NO_ERROR:
96            print("Success. Response: ", msgpack.unpackb(data))
97            # now that we have the response in a structured format, we could
98            # further deserialize it to a Python object, depending on our needs.
99
100        elif resp_code == IN_RESPONSE_CLIENT_ERROR:
101            print("Invalid Request. Details: ", msgpack.unpackb(data))
102
103        elif resp_code == IN_RESPONSE_SERVER_ERROR:
104            print("Internal Error. Details: ", msgpack.unpackb(data))
105
106        else:
107            print("Unknown response. Update the client. Additional data:", data)
108
109        # As we only sent one request, we must break after
110        # receiving its response.
111        break
112    else:
113        continue
114
115    break  # break after receiving one message. See above for why.
116