blob: 64546c020551996fdaf9d7665126b8180486c54c [file] [log] [blame]
Bram Moolenaard7ece102016-02-02 23:23:02 +01001#!/usr/bin/python
2#
3# Server that will accept connections from a Vim channel.
4# Run this server and then in Vim you can open the channel:
5# :let handle = ch_open('localhost:8765', 'json')
6#
7# Then Vim can send requests to the server:
8# :let response = ch_sendexpr(handle, 'hello!')
9#
Bram Moolenaard7ece102016-02-02 23:23:02 +010010# See ":help channel-demo" in Vim.
11#
12# This requires Python 2.6 or later.
13
14from __future__ import print_function
15import json
16import socket
17import sys
18import threading
19
20try:
21 # Python 3
22 import socketserver
23except ImportError:
24 # Python 2
25 import SocketServer as socketserver
26
27thesocket = None
28
29class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
30
31 def handle(self):
32 print("=== socket opened ===")
33 global thesocket
34 thesocket = self.request
35 while True:
36 try:
37 data = self.request.recv(4096).decode('utf-8')
38 except socket.error:
39 print("=== socket error ===")
40 break
41 except IOError:
42 print("=== socket closed ===")
43 break
44 if data == '':
45 print("=== socket closed ===")
46 break
47 print("received: {}".format(data))
48 try:
49 decoded = json.loads(data)
50 except ValueError:
51 print("json decoding failed")
52 decoded = [-1, '']
53
54 # Send a response if the sequence number is positive.
Bram Moolenaard7ece102016-02-02 23:23:02 +010055 if decoded[0] >= 0:
56 if decoded[1] == 'hello!':
57 # simply send back a string
58 response = "got it"
59 elif decoded[1] == 'make change':
60 # Send two ex commands at the same time, before replying to
61 # the request.
62 cmd = '["ex","call append(\\"$\\",\\"added1\\")"]'
63 cmd += '["ex","call append(\\"$\\",\\"added2\\")"]'
64 print("sending: {}".format(cmd))
65 thesocket.sendall(cmd.encode('utf-8'))
66 response = "ok"
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +010067 elif decoded[1] == 'eval-works':
68 # Send an eval request. We ignore the response.
69 cmd = '["eval","\\"foo\\" . 123", -1]'
70 print("sending: {}".format(cmd))
71 thesocket.sendall(cmd.encode('utf-8'))
72 response = "ok"
73 elif decoded[1] == 'eval-fails':
74 # Send an eval request that will fail.
75 cmd = '["eval","xxx", -2]'
76 print("sending: {}".format(cmd))
77 thesocket.sendall(cmd.encode('utf-8'))
78 response = "ok"
79 elif decoded[1] == 'eval-result':
80 # Send back the last received eval result.
81 response = last_eval
Bram Moolenaard7ece102016-02-02 23:23:02 +010082 elif decoded[1] == '!quit!':
83 # we're done
84 sys.exit(0)
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +010085 elif decoded[1] == '!crash!':
86 # Crash!
87 42 / 0
Bram Moolenaard7ece102016-02-02 23:23:02 +010088 else:
89 response = "what?"
90
91 encoded = json.dumps([decoded[0], response])
92 print("sending: {}".format(encoded))
93 thesocket.sendall(encoded.encode('utf-8'))
94
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +010095 # Negative numbers are used for "eval" responses.
96 elif decoded[0] < 0:
97 last_eval = decoded
98
Bram Moolenaard7ece102016-02-02 23:23:02 +010099 thesocket = None
100
101class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
102 pass
103
104if __name__ == "__main__":
105 HOST, PORT = "localhost", 0
106
107 server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
108 ip, port = server.server_address
109
110 # Start a thread with the server -- that thread will then start one
111 # more thread for each request
112 server_thread = threading.Thread(target=server.serve_forever)
113
114 # Exit the server thread when the main thread terminates
115 server_thread.daemon = True
116 server_thread.start()
117
118 # Write the port number in Xportnr, so that the test knows it.
119 f = open("Xportnr", "w")
120 f.write("{}".format(port))
121 f.close()
122
123 # Block here
124 print("Listening on port {}".format(port))
125 server.serve_forever()