87 lines
2.9 KiB
Python
87 lines
2.9 KiB
Python
import asyncio
|
|
import functools
|
|
import json
|
|
import os
|
|
import socket
|
|
import struct
|
|
|
|
|
|
async def get_user_home(name:str):
|
|
# Check args
|
|
if not isinstance(name, str):
|
|
raise TypeError("name have to be a string.")
|
|
|
|
# Find home
|
|
proc = await asyncio.create_subprocess_exec(b"getent", b"passwd", name.encode(), stdout=asyncio.subprocess.PIPE)
|
|
proc_data = await proc.communicate()
|
|
if not isinstance(proc_data, tuple):
|
|
raise RuntimeError("Internal value isn't the expected type.")
|
|
if proc.returncode != 0:
|
|
raise RuntimeError("getent didn't work.")
|
|
return proc_data[0].decode().split(":")[6]
|
|
|
|
|
|
async def run_access_socket(path:str, async_callback, fork:bool):
|
|
async def run_func(read, write):
|
|
# Get user id
|
|
sock = write.get_extra_info("socket")
|
|
tmp = sock.getsockopt(socket.SOL_SOCKET, socket.SO_PEERCRED, struct.calcsize('3i'))
|
|
tmp = struct.unpack('3i', tmp)[1]
|
|
uid = str(tmp)
|
|
|
|
# Run callback
|
|
await async_callback(read, write, uid)
|
|
server = await asyncio.start_unix_server(run_func, path=path)
|
|
os.chmod(path, 0o666)
|
|
if fork:
|
|
if os.fork() != 0:
|
|
exit(0)
|
|
await server.serve_forever()
|
|
|
|
|
|
_format_length = struct.Struct(">I")
|
|
def rpc_callback(async_func):
|
|
@functools.wraps(async_func)
|
|
async def wrap_func(read, write, uid):
|
|
while not read.at_eof():
|
|
# Read data
|
|
try:
|
|
size = _format_length.unpack(await read.readexactly(_format_length.size))
|
|
except asyncio.exceptions.IncompleteReadError:
|
|
return # Client closed normaly
|
|
data = json.loads((await read.readexactly(size)).decode("UTF-8"))
|
|
|
|
# Callback and return result
|
|
result = json.dumps(await async_func(data, uid)).encode("UTF-8")
|
|
write.write(_format_length.pack(len(result)))
|
|
write.write(result)
|
|
await write.drain()
|
|
return wrap_func
|
|
|
|
|
|
class Connection():
|
|
__read = None
|
|
__write = None
|
|
__lock = asyncio.Lock()
|
|
|
|
async def init(self, sys_socket):
|
|
self.__read, self.__write = await asyncio.open_unix_connection(path=sys_socket)
|
|
|
|
async def call(self, data:dict):
|
|
# Check data and state
|
|
if self.__read is None or self.__write is None:
|
|
raise RuntimeError("Connection isn't inited.")
|
|
if not isinstance(data, dict):
|
|
raise TypeError("data have to be a dict")
|
|
|
|
# Wait for access
|
|
async with self.__lock:
|
|
# Send data
|
|
data = json.dumps(data).encode("UTF-8")
|
|
self.__write.write(_format_length.pack(len(data)))
|
|
self.__write.write(data)
|
|
await self.__write.drain()
|
|
|
|
# Recive date and return
|
|
size = _format_length.unpack(await self.__read.readexactly(_format_length.size))
|
|
return json.loads((await self.__read.readexactly(size)).decode("UTF-8")) |