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 JsonDocument 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
49
50import json
51import msgpack
52
53from spyne.util.six import BytesIO
54
55s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
56s.connect(("localhost", 5551))
57
58request_document = {"say_hello": ["Dave", 5]}
59
60# Because the server's input protocol is JsonDocument, we serialize the
61# request document to json bytestream.
62request_bytestream = json.dumps(request_document)
63
64# Because our server side transport is msgpack, we put the request bytestream
65# inside a MessagePack document.
66request_wrapper_document = [OUT_REQUEST, request_bytestream]
67
68# and we serialize the request wrapper document to msgpack bytestream as well
69request_wrapper_bytestream = msgpack.packb(request_wrapper_document)
70
71# Some numbers to show how efficient this is:
72print("Raw message length:", len(request_bytestream))
73print("Wrapped message length:", len(request_wrapper_bytestream))
74print("Overhead:", len(request_wrapper_bytestream) - len(request_bytestream),
75      "byte(s).")
76
77# which we push to the socket.
78s.sendall(request_wrapper_bytestream)
79
80# This is straight from Python example in msgpack.org
81in_buffer = msgpack.Unpacker()
82
83while True:
84    # We wait for the full message to arrive.
85    in_buffer.feed(s.recv(1))
86
87    # Again, straight from the Python example in MessagePack homepage.
88    for msg in in_buffer:
89        print("Raw response document:", msg)
90
91        # There should be only one entry in the response dict. We ignore the
92        # rest here but we could whine about invalid response just as well.
93        resp_code, data = iter(msg.items()).next()
94
95        # We finally parse the response. We should probably be doing a dict
96        # lookup here instead.
97        if resp_code == IN_RESPONSE_NO_ERROR:
98            print("Success. Response: ", json.loads(data))
99            # now that we have the response in a structured format, we could
100            # further deserialize it to a Python object, depending on our needs.
101
102        elif resp_code == IN_RESPONSE_CLIENT_ERROR:
103            print("Invalid Request. Details: ", json.loads(data))
104
105        elif resp_code == IN_RESPONSE_SERVER_ERROR:
106            print("Internal Error. Details: ", json.loads(data))
107
108        else:
109            print("Unknown response. Update the client. Additional data:", data)
110
111        # As we only sent one request, we must break after
112        # receiving its response.
113        break
114    else:
115        continue
116
117    break  # break after receiving one message. See above for why.
118