blob: 66fd48f43addd1e0371bd841ce848793e9a00654 [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.
Bram Moolenaar77073442016-02-13 23:23:53 +01004# Used by test_channel.vim.
Bram Moolenaard7ece102016-02-02 23:23:02 +01005#
6# This requires Python 2.6 or later.
7
8from __future__ import print_function
9import json
10import socket
11import sys
Bram Moolenaar81661fb2016-02-18 22:23:34 +010012import time
Bram Moolenaard7ece102016-02-02 23:23:02 +010013import threading
14
15try:
16 # Python 3
17 import socketserver
18except ImportError:
19 # Python 2
20 import SocketServer as socketserver
21
Bram Moolenaard7ece102016-02-02 23:23:02 +010022class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
23
24 def handle(self):
25 print("=== socket opened ===")
Bram Moolenaard7ece102016-02-02 23:23:02 +010026 while True:
27 try:
Bram Moolenaar608a8912016-02-03 22:39:51 +010028 received = self.request.recv(4096).decode('utf-8')
Bram Moolenaard7ece102016-02-02 23:23:02 +010029 except socket.error:
30 print("=== socket error ===")
31 break
32 except IOError:
33 print("=== socket closed ===")
34 break
Bram Moolenaar608a8912016-02-03 22:39:51 +010035 if received == '':
Bram Moolenaard7ece102016-02-02 23:23:02 +010036 print("=== socket closed ===")
37 break
Bram Moolenaar608a8912016-02-03 22:39:51 +010038 print("received: {}".format(received))
Bram Moolenaard7ece102016-02-02 23:23:02 +010039
Bram Moolenaare7bed622016-02-03 22:20:29 +010040 # We may receive two messages at once. Take the part up to the
41 # matching "]" (recognized by finding "][").
Bram Moolenaar608a8912016-02-03 22:39:51 +010042 todo = received
43 while todo != '':
44 splitidx = todo.find('][')
Bram Moolenaare7bed622016-02-03 22:20:29 +010045 if splitidx < 0:
Bram Moolenaar608a8912016-02-03 22:39:51 +010046 used = todo
47 todo = ''
Bram Moolenaard7ece102016-02-02 23:23:02 +010048 else:
Bram Moolenaar608a8912016-02-03 22:39:51 +010049 used = todo[:splitidx + 1]
50 todo = todo[splitidx + 1:]
51 if used != received:
52 print("using: {}".format(used))
Bram Moolenaard7ece102016-02-02 23:23:02 +010053
Bram Moolenaare7bed622016-02-03 22:20:29 +010054 try:
Bram Moolenaar608a8912016-02-03 22:39:51 +010055 decoded = json.loads(used)
Bram Moolenaare7bed622016-02-03 22:20:29 +010056 except ValueError:
57 print("json decoding failed")
58 decoded = [-1, '']
Bram Moolenaard7ece102016-02-02 23:23:02 +010059
Bram Moolenaare7bed622016-02-03 22:20:29 +010060 # Send a response if the sequence number is positive.
61 if decoded[0] >= 0:
62 if decoded[1] == 'hello!':
63 # simply send back a string
64 response = "got it"
65 elif decoded[1] == 'make change':
Bram Moolenaar66624ff2016-02-03 23:59:43 +010066 # Send two ex commands at the same time, before
67 # replying to the request.
Bram Moolenaare7bed622016-02-03 22:20:29 +010068 cmd = '["ex","call append(\\"$\\",\\"added1\\")"]'
69 cmd += '["ex","call append(\\"$\\",\\"added2\\")"]'
70 print("sending: {}".format(cmd))
Bram Moolenaar3b05b132016-02-03 23:25:07 +010071 self.request.sendall(cmd.encode('utf-8'))
Bram Moolenaare7bed622016-02-03 22:20:29 +010072 response = "ok"
Bram Moolenaarf4160862016-02-05 23:09:12 +010073 elif decoded[1] == 'do normal':
74 # Send a normal command.
75 cmd = '["normal","G$s more\u001b"]'
76 print("sending: {}".format(cmd))
77 self.request.sendall(cmd.encode('utf-8'))
78 response = "ok"
Bram Moolenaare7bed622016-02-03 22:20:29 +010079 elif decoded[1] == 'eval-works':
80 # Send an eval request. We ignore the response.
81 cmd = '["eval","\\"foo\\" . 123", -1]'
82 print("sending: {}".format(cmd))
Bram Moolenaar3b05b132016-02-03 23:25:07 +010083 self.request.sendall(cmd.encode('utf-8'))
Bram Moolenaare7bed622016-02-03 22:20:29 +010084 response = "ok"
85 elif decoded[1] == 'eval-fails':
86 # Send an eval request that will fail.
87 cmd = '["eval","xxx", -2]'
88 print("sending: {}".format(cmd))
Bram Moolenaar3b05b132016-02-03 23:25:07 +010089 self.request.sendall(cmd.encode('utf-8'))
Bram Moolenaare7bed622016-02-03 22:20:29 +010090 response = "ok"
Bram Moolenaar55fab432016-02-07 16:53:13 +010091 elif decoded[1] == 'eval-error':
92 # Send an eval request that works but the result can't
93 # be encoded.
94 cmd = '["eval","function(\\"tr\\")", -3]'
95 print("sending: {}".format(cmd))
96 self.request.sendall(cmd.encode('utf-8'))
97 response = "ok"
Bram Moolenaar66624ff2016-02-03 23:59:43 +010098 elif decoded[1] == 'eval-bad':
99 # Send an eval request missing the third argument.
100 cmd = '["eval","xxx"]'
101 print("sending: {}".format(cmd))
102 self.request.sendall(cmd.encode('utf-8'))
103 response = "ok"
Bram Moolenaarf4160862016-02-05 23:09:12 +0100104 elif decoded[1] == 'an expr':
105 # Send an expr request.
106 cmd = '["expr","setline(\\"$\\", [\\"one\\",\\"two\\",\\"three\\"])"]'
107 print("sending: {}".format(cmd))
108 self.request.sendall(cmd.encode('utf-8'))
109 response = "ok"
110 elif decoded[1] == 'redraw':
111 cmd = '["redraw",""]'
112 print("sending: {}".format(cmd))
113 self.request.sendall(cmd.encode('utf-8'))
114 response = "ok"
115 elif decoded[1] == 'redraw!':
116 cmd = '["redraw","force"]'
117 print("sending: {}".format(cmd))
118 self.request.sendall(cmd.encode('utf-8'))
119 response = "ok"
Bram Moolenaar6076fe12016-02-05 22:49:56 +0100120 elif decoded[1] == 'empty-request':
121 cmd = '[]'
122 print("sending: {}".format(cmd))
123 self.request.sendall(cmd.encode('utf-8'))
124 response = "ok"
Bram Moolenaare7bed622016-02-03 22:20:29 +0100125 elif decoded[1] == 'eval-result':
126 # Send back the last received eval result.
127 response = last_eval
Bram Moolenaarf6157282016-02-10 21:07:14 +0100128 elif decoded[1] == 'call me':
129 cmd = '[0,"we called you"]'
130 print("sending: {}".format(cmd))
131 self.request.sendall(cmd.encode('utf-8'))
132 response = "ok"
133 elif decoded[1] == 'call me again':
134 cmd = '[0,"we did call you"]'
135 print("sending: {}".format(cmd))
136 self.request.sendall(cmd.encode('utf-8'))
137 response = ""
Bram Moolenaare7bed622016-02-03 22:20:29 +0100138 elif decoded[1] == '!quit!':
139 # we're done
Bram Moolenaarb3e2f002016-02-04 00:11:37 +0100140 self.server.shutdown()
Bram Moolenaarb92abad2016-02-08 22:37:24 +0100141 return
Bram Moolenaare7bed622016-02-03 22:20:29 +0100142 elif decoded[1] == '!crash!':
143 # Crash!
144 42 / 0
145 else:
146 response = "what?"
147
Bram Moolenaarf6157282016-02-10 21:07:14 +0100148 if response == "":
149 print("no response")
150 else:
151 encoded = json.dumps([decoded[0], response])
152 print("sending: {}".format(encoded))
153 self.request.sendall(encoded.encode('utf-8'))
Bram Moolenaare7bed622016-02-03 22:20:29 +0100154
155 # Negative numbers are used for "eval" responses.
156 elif decoded[0] < 0:
157 last_eval = decoded
Bram Moolenaarfcb1e3d2016-02-03 21:32:46 +0100158
Bram Moolenaard7ece102016-02-02 23:23:02 +0100159class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
160 pass
161
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100162def writePortInFile(port):
163 # Write the port number in Xportnr, so that the test knows it.
164 f = open("Xportnr", "w")
165 f.write("{}".format(port))
166 f.close()
167
Bram Moolenaard7ece102016-02-02 23:23:02 +0100168if __name__ == "__main__":
169 HOST, PORT = "localhost", 0
170
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100171 # Wait half a second before opening the port to test waittime in ch_open().
172 # We do want to get the port number, get that first. We cannot open the
173 # socket, guess a port is free.
174 if len(sys.argv) >= 2 and sys.argv[1] == 'delay':
175 PORT = 13684
176 writePortInFile(PORT)
177
178 print("Wait for it...")
179 time.sleep(0.5)
180
Bram Moolenaard7ece102016-02-02 23:23:02 +0100181 server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
182 ip, port = server.server_address
183
Bram Moolenaar6076fe12016-02-05 22:49:56 +0100184 # Start a thread with the server. That thread will then start a new thread
185 # for each connection.
Bram Moolenaard7ece102016-02-02 23:23:02 +0100186 server_thread = threading.Thread(target=server.serve_forever)
Bram Moolenaard7ece102016-02-02 23:23:02 +0100187 server_thread.start()
188
Bram Moolenaar81661fb2016-02-18 22:23:34 +0100189 writePortInFile(port)
Bram Moolenaard7ece102016-02-02 23:23:02 +0100190
Bram Moolenaard7ece102016-02-02 23:23:02 +0100191 print("Listening on port {}".format(port))
Bram Moolenaarb3e2f002016-02-04 00:11:37 +0100192
193 # Main thread terminates, but the server continues running
194 # until server.shutdown() is called.
Bram Moolenaarddbe7d22016-02-20 18:26:48 +0100195 try:
196 while server_thread.isAlive():
197 server_thread.join(1)
198 except (KeyboardInterrupt, SystemExit):
199 server.shutdown()