File: mcdataservice.py

package info (click to toggle)
mccode 3.5.19%2Bds5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,113,256 kB
  • sloc: ansic: 40,697; python: 25,137; yacc: 8,438; sh: 5,405; javascript: 4,596; lex: 1,632; cpp: 742; perl: 296; lisp: 273; makefile: 226; fortran: 132
file content (149 lines) | stat: -rw-r--r-- 4,545 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
'''
A "pickle" server and client implementation incapsulating request and reply implementations, 
along with implementations suitable for sending mccode data graph and a simple string reply
combined with a server listdir() output.

This can be used to set up remote mccode data browsing with low requirements.
'''
import sys
import os
import socket
import pickle
from threading import Thread

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
from mccodelib.mcplotloader import McCodeDataLoader

'''
Protocol implementation.
'''
class RemoteCommand(object):
    ''' subclass and implement impl, which should return a RemoteReply instance '''
    def handle(self, reply_sender):
        ''' reply_sender is a ReplyPickleSender '''
        reply = self.impl()
        reply_sender.send_reply(reply)

class RemoteReply(object):
    ''' subclass to implement server replies, NOTE: pickle.loads does not invoke __init__() '''
    def __init__(self):
        pass

class RCSimFile(RemoteCommand):
    def __init__(self, simfile):
        self.simfile = simfile
    
    def impl(self):
        loader = McCodeDataLoader(simfile=self.simfile)
        loader.load()
        graph = loader.plot_graph
        
        reply = RRSimfile(graph)
        return reply
    
    def __str__(self):
        return 'loading simfile: %s' % self.simfile

class RRSimfile(RemoteReply):
    def __init__(self, plotgraph):
        self.plotgraph = plotgraph

class RCList(RemoteCommand):
    def impl(self):
        lst = os.listdir('.')
        text = '\n'.join(lst)
        
        reply = RRList(text)
        return reply

class RRList(RemoteReply):
    def __init__(self, text):
        self.text = text

'''
Client / server implementation.
'''
class McDataPickleClient(object):
    ''' receives, unpickles and dispatches RemoteCommand objects '''
    def __init__(self, port):

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_address = ('localhost', port)
        print('connecting to %s port %s' % server_address)
        self.sock.connect(server_address)
        self.sock.settimeout(0.5)
    
    def ask(self, request):
        try:
            print('sending request: "%s"' % request)
            
            text = pickle.dumps(request)
            self.sock.sendall(text)
            
            text = ''
            while True:
                try:
                    data = self.sock.recv(1024)
                    if data == '':
                        break
                    else:
                        text = text + data
                except Exception as e:
                    print('timeout reached')
            
            self.reply = pickle.loads(text)
            
        finally:
            self.sock.close()

class McDataPickleServer(object):
    ''' receives, unpickles and dispatches RemoteCommand objects '''
    def __init__(self, port):
        '''  '''
        self.port = port
        
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_name = 'localhost'
        server_address = (server_name, self.port)
        print('starting up on %s port %s' % server_address)
        self.sock.bind(server_address)
        self.sock.listen(1)
    
    def listen(self):
        ''' execution loop '''
        
        try:
            while True:
                print('waiting for a connection...')
                connection, client_address = self.sock.accept()
                print('client connected:', client_address)
                text = ''
                
                # NOTE: right now we assume, that we can get it all in one chunk with a blocking socket
                data = connection.recv(1024)
                text = text + data
                
                # unpickle and dispatch
                request = pickle.loads(text)
                print('received request: "%s"' % request)
                
                t = Thread()
                rsend = ReplyPickleSender(connection)
                t.run = lambda: request.handle(rsend)
                t.start()
        finally:
            self.sock.close()

class ReplyPickleSender():
    def __init__(self, connection):
        self.connection = connection
    
    def send_reply(self, reply):
        ''' callback for dispatched handlers - sends a reply though the socket '''
        try:
            s = pickle.dumps(reply)
            print("sending data...")
            self.connection.sendall(s)
        finally:
            self.connection.close()