Sans-IO pattern, language server protocol implementation
Project description
Language Server Protocol implementation in sans-io pattern. Which is highly inspired by [[https://sans-io.readthedocs.io/how-to-sans-io.html][Sans-IO pattern]]. And some relatived projects: [[https://github.com/python-hyper/hyper-h2][hyper-h2]], [[https://github.com/python-hyper/h11][h11]]
So the actual language server can build on this, it can be integreted with trio, asyncio, or some other frameworks.
* Required python version
Python >= 3.6
* How to install it
There are two ways to install lsp:
- install via pip (recommended)
#+BEGIN_SRC shell
pip install lsp
#+END_SRC
- install via setup.py
#+BEGIN_SRC shell
python setup.py install
#+END_SRC
* Basic Usage example
** For client
#+BEGIN_SRC python
import socket
from lsp import Connection, NEED_DATA, DataReceived, MessageEnd
sock = socket.socket()
sock.connect(("localhost", 10001))
conn = Connection("client")
answer = input("Send request?(y/n)")
while answer == "y":
# use connection send_json method to convert json object to bytes
request_data = conn.send_json({"method": "didOpen"})
# then we can send data to server
sock.sendall(request_data)
while True:
# and then we can get next_event of connection, it can indicate
# that what should we do.
event = conn.next_event()
# we need to receive data from server
if event is NEED_DATA:
try:
data = sock.recv(1024)
except ConnectionResetError:
print('The server connection is closed, So I will leave:)')
conn.close()
sock.close()
exit(0)
else:
print("return from sock.recv")
conn.receive(data)
# we have receive data from server
elif isinstance(event, DataReceived):
print("Receive event, content:")
print(event)
elif isinstance(event, MessageEnd):
print("Server sending data complete.")
break
# then we can call get_received_data() to extract out what we get
header, response_body = conn.get_received_data()
print("Response header from server:")
print(header)
print("Response body from server:")
print(response_body)
answer = input("Send request?(y/n)")
conn.go_next_circle()
#+END_SRC
For more usage example, please check out files in *examples/clients* folder.
** For server
#+BEGIN_SRC python
import socket
from lsp import Connection, NEED_DATA, RequestReceived, DataReceived, MessageEnd
sock = socket.socket()
sock.bind(("0.0.0.0", 10001))
sock.listen(1)
client_sock, addr = sock.accept()
print(f"get connection from {client_sock}")
conn = Connection("server")
try:
while True:
while True:
# call next event to indicate what server socket should do.
event = conn.next_event()
# no data coming yet, so the return value is NEED_DATA
if event is NEED_DATA:
data = client_sock.recv(1024)
if data == b"":
print("Client connection is closed, I will exit.")
exit(0)
conn.receive(data)
# Request header is coming :)
elif isinstance(event, RequestReceived):
print("Receive request header")
print(event.to_data())
# Request data is coming :)
elif isinstance(event, DataReceived):
print("Receive request data")
print(event.to_data())
# client has send data completely.
elif isinstance(event, MessageEnd):
print("Data receive complete:)")
break
# so we can call con.get_received_data to fetch what client send.
received_data = conn.get_received_data()
print(f"Receiving data: {received_data}")
# send response back to client.
print(f"Sending response to client")
data = conn.send_json({"Content": "I am received:)"})
client_sock.sendall(data)
print(f"For now, go to next circle")
# then we need to call go_next_circle, to get another request from client.
conn.go_next_circle()
finally:
sock.close()
#+END_SRC
For more usage example, please check out files in *examples/servers* folder.
* Main API
1. Want to send json data? You can try =conn.send_json=.
2. Want to know what we should do next? You can try =conn.next_event=.
3. After receive data, please don't forget to call =conn.receive(data)=. Which will save data into inner buffer, and it can drive =conn.next_event= method returns other events.
* Main events we will get from next_event
** Client
Client side will get the following values from next_events:
1. NEED_DATA - which indicate that we need to receive data from server.
2. ResponseReceived - Client have receive response header.
3. DataReceived - Client have receive resposne body.
4. MessageEnd - Receive data from server complete.
** Server
Server side will get the following values from next_events:
1. NEED_DATA - which indicate that we need to receive data from client.
2. RequestReceived - Client have send request header, and we receive it.
3. DataReceived - Server have receive response body from client.
4. MessageEnd - Client sending request complete.
So the actual language server can build on this, it can be integreted with trio, asyncio, or some other frameworks.
* Required python version
Python >= 3.6
* How to install it
There are two ways to install lsp:
- install via pip (recommended)
#+BEGIN_SRC shell
pip install lsp
#+END_SRC
- install via setup.py
#+BEGIN_SRC shell
python setup.py install
#+END_SRC
* Basic Usage example
** For client
#+BEGIN_SRC python
import socket
from lsp import Connection, NEED_DATA, DataReceived, MessageEnd
sock = socket.socket()
sock.connect(("localhost", 10001))
conn = Connection("client")
answer = input("Send request?(y/n)")
while answer == "y":
# use connection send_json method to convert json object to bytes
request_data = conn.send_json({"method": "didOpen"})
# then we can send data to server
sock.sendall(request_data)
while True:
# and then we can get next_event of connection, it can indicate
# that what should we do.
event = conn.next_event()
# we need to receive data from server
if event is NEED_DATA:
try:
data = sock.recv(1024)
except ConnectionResetError:
print('The server connection is closed, So I will leave:)')
conn.close()
sock.close()
exit(0)
else:
print("return from sock.recv")
conn.receive(data)
# we have receive data from server
elif isinstance(event, DataReceived):
print("Receive event, content:")
print(event)
elif isinstance(event, MessageEnd):
print("Server sending data complete.")
break
# then we can call get_received_data() to extract out what we get
header, response_body = conn.get_received_data()
print("Response header from server:")
print(header)
print("Response body from server:")
print(response_body)
answer = input("Send request?(y/n)")
conn.go_next_circle()
#+END_SRC
For more usage example, please check out files in *examples/clients* folder.
** For server
#+BEGIN_SRC python
import socket
from lsp import Connection, NEED_DATA, RequestReceived, DataReceived, MessageEnd
sock = socket.socket()
sock.bind(("0.0.0.0", 10001))
sock.listen(1)
client_sock, addr = sock.accept()
print(f"get connection from {client_sock}")
conn = Connection("server")
try:
while True:
while True:
# call next event to indicate what server socket should do.
event = conn.next_event()
# no data coming yet, so the return value is NEED_DATA
if event is NEED_DATA:
data = client_sock.recv(1024)
if data == b"":
print("Client connection is closed, I will exit.")
exit(0)
conn.receive(data)
# Request header is coming :)
elif isinstance(event, RequestReceived):
print("Receive request header")
print(event.to_data())
# Request data is coming :)
elif isinstance(event, DataReceived):
print("Receive request data")
print(event.to_data())
# client has send data completely.
elif isinstance(event, MessageEnd):
print("Data receive complete:)")
break
# so we can call con.get_received_data to fetch what client send.
received_data = conn.get_received_data()
print(f"Receiving data: {received_data}")
# send response back to client.
print(f"Sending response to client")
data = conn.send_json({"Content": "I am received:)"})
client_sock.sendall(data)
print(f"For now, go to next circle")
# then we need to call go_next_circle, to get another request from client.
conn.go_next_circle()
finally:
sock.close()
#+END_SRC
For more usage example, please check out files in *examples/servers* folder.
* Main API
1. Want to send json data? You can try =conn.send_json=.
2. Want to know what we should do next? You can try =conn.next_event=.
3. After receive data, please don't forget to call =conn.receive(data)=. Which will save data into inner buffer, and it can drive =conn.next_event= method returns other events.
* Main events we will get from next_event
** Client
Client side will get the following values from next_events:
1. NEED_DATA - which indicate that we need to receive data from server.
2. ResponseReceived - Client have receive response header.
3. DataReceived - Client have receive resposne body.
4. MessageEnd - Receive data from server complete.
** Server
Server side will get the following values from next_events:
1. NEED_DATA - which indicate that we need to receive data from client.
2. RequestReceived - Client have send request header, and we receive it.
3. DataReceived - Server have receive response body from client.
4. MessageEnd - Client sending request complete.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
lsp-0.1.0.tar.gz
(11.7 kB
view details)
Built Distribution
lsp-0.1.0-py3.7.egg
(26.2 kB
view details)
File details
Details for the file lsp-0.1.0.tar.gz
.
File metadata
- Download URL: lsp-0.1.0.tar.gz
- Upload date:
- Size: 11.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.3 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.0rc1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 06d49b283d0fcdd848d44c0839cd935a839add4920bd74e270d8761131ae3f1e |
|
MD5 | 6bfb1ed3051ccc60b758e89f245457e3 |
|
BLAKE2b-256 | 0fbce11e6033055977cedf86b2cf0156da604afe29617933d4b33d7ddcd71fae |
File details
Details for the file lsp-0.1.0-py3.7.egg
.
File metadata
- Download URL: lsp-0.1.0-py3.7.egg
- Upload date:
- Size: 26.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.3 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.0rc1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 191f4306e283a058c46322fabf83e720eb4b3dff35cc28599ea6e0a3a2440640 |
|
MD5 | 27f49214993312573af4b671a428433e |
|
BLAKE2b-256 | eda8796871383980c3c4d60388f456e7175d7a1dd8929575d0cda04d6db52b24 |