blob: a706243e4390afc7b0369c2f508aee6c0a5efdf6 [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#
10# And you can control Vim by typing a JSON message here, e.g.:
11# ["ex","echo 'hi there'"]
12#
13# There is no prompt, just type a line and press Enter.
14# To exit cleanly type "quit<Enter>".
15#
16# See ":help channel-demo" in Vim.
17#
18# This requires Python 2.6 or later.
19
20from __future__ import print_function
21import json
22import socket
23import sys
24import threading
25
26try:
27 # Python 3
28 import socketserver
29except ImportError:
30 # Python 2
31 import SocketServer as socketserver
32
33thesocket = None
34
35class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
36
37 def handle(self):
38 print("=== socket opened ===")
39 global thesocket
40 thesocket = self.request
41 while True:
42 try:
43 data = self.request.recv(4096).decode('utf-8')
44 except socket.error:
45 print("=== socket error ===")
46 break
47 except IOError:
48 print("=== socket closed ===")
49 break
50 if data == '':
51 print("=== socket closed ===")
52 break
53 print("received: {}".format(data))
54 try:
55 decoded = json.loads(data)
56 except ValueError:
57 print("json decoding failed")
58 decoded = [-1, '']
59
60 # Send a response if the sequence number is positive.
61 # Negative numbers are used for "eval" responses.
62 if decoded[0] >= 0:
63 if decoded[1] == 'hello!':
64 # simply send back a string
65 response = "got it"
66 elif decoded[1] == 'make change':
67 # Send two ex commands at the same time, before replying to
68 # the request.
69 cmd = '["ex","call append(\\"$\\",\\"added1\\")"]'
70 cmd += '["ex","call append(\\"$\\",\\"added2\\")"]'
71 print("sending: {}".format(cmd))
72 thesocket.sendall(cmd.encode('utf-8'))
73 response = "ok"
74 elif decoded[1] == '!quit!':
75 # we're done
76 sys.exit(0)
77 else:
78 response = "what?"
79
80 encoded = json.dumps([decoded[0], response])
81 print("sending: {}".format(encoded))
82 thesocket.sendall(encoded.encode('utf-8'))
83
84 thesocket = None
85
86class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
87 pass
88
89if __name__ == "__main__":
90 HOST, PORT = "localhost", 0
91
92 server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
93 ip, port = server.server_address
94
95 # Start a thread with the server -- that thread will then start one
96 # more thread for each request
97 server_thread = threading.Thread(target=server.serve_forever)
98
99 # Exit the server thread when the main thread terminates
100 server_thread.daemon = True
101 server_thread.start()
102
103 # Write the port number in Xportnr, so that the test knows it.
104 f = open("Xportnr", "w")
105 f.write("{}".format(port))
106 f.close()
107
108 # Block here
109 print("Listening on port {}".format(port))
110 server.serve_forever()