Windows friendly solution.

This commit is contained in:
retoor 2025-05-13 18:32:59 +02:00
parent ac2f68f93f
commit a4bea94495
9 changed files with 66 additions and 43 deletions

View File

@ -20,7 +20,6 @@ serve: run
run:
.venv/bin/snek serve
#$(GUNICORN) -w $(GUNICORN_WORKERS) -k aiohttp.worker.GunicornWebWorker snek.gunicorn:app --bind 0.0.0.0:$(PORT) --reload
install: ubuntu
python3.12 -m venv .venv

View File

@ -18,7 +18,8 @@ dependencies = [
"lxml",
"IPython",
"shed",
"app @ git+https://retoor.molodetz.nl/retoor/app",
"app @ git+https://retoor.molodetz.nl/retoor/app.git",
"zhurnal @git+https://retoor.molodetz.nl/retoor/zhurnal.git",
"beautifulsoup4",
"gunicorn",
"imgkit",

View File

@ -1,24 +1,45 @@
import click
import uvloop
from aiohttp import web
import asyncio
from snek.app import Application
from IPython import start_ipython
import sqlite3
import pathlib
import shutil
@click.group()
def cli():
pass
@cli.command()
@click.option('--db_path',default="snek.db", help='Database to initialize if not exists.')
@click.option('--source',default=None, help='Database to initialize if not exists.')
def init(db_path,source):
if source and pathlib.Path(source).exists():
print(f"Copying {source} to {db_path}")
shutil.copy2(source,db_path)
print("Database initialized.")
return
if pathlib.Path(db_path).exists():
return
print(f"Initializing database at {db_path}")
db = sqlite3.connect(db_path)
db.cursor().executescript(
pathlib.Path(__file__).parent.joinpath("schema.sql").read_text()
)
db.commit()
db.close()
print("Database initialized.")
@cli.command()
@click.option('--port', default=8081, show_default=True, help='Port to run the application on')
@click.option('--host', default='0.0.0.0', show_default=True, help='Host to run the application on')
@click.option('--db_path', default='snek.db', show_default=True, help='Database path for the application')
def serve(port, host, db_path):
try:
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
except ImportError:
print("uvloop not installed, using default event loop.")
#init(db_path)
#asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
web.run_app(
Application(db_path=f"sqlite:///{db_path}"), port=port, host=host
)

View File

@ -3,9 +3,9 @@ import logging
import pathlib
import time
import uuid
from snek import snode
from snek.view.threads import ThreadsView
import json
logging.basicConfig(level=logging.DEBUG)
from concurrent.futures import ThreadPoolExecutor
@ -57,7 +57,6 @@ from snek.view.web import WebView
from snek.view.channel import ChannelAttachmentView
from snek.webdav import WebdavApplication
from snek.sgit import GitApplication
SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
@ -99,18 +98,26 @@ class Application(BaseApplication):
self.ssh_host = "0.0.0.0"
self.ssh_port = 2242
self.setup_router()
self.ssh_server = None
self.ssh_server = None
self.sync_service = None
self.executor = None
self.cache = Cache(self)
self.services = get_services(app=self)
self.mappers = get_mappers(app=self)
self.broadcast_service = None
self.on_startup.append(self.start_ssh_server)
self.on_startup.append(self.prepare_asyncio)
self.on_startup.append(self.prepare_database)
async def snode_sync(self, app):
self.sync_service = asyncio.create_task(snode.sync_service(app))
async def start_ssh_server(self, app):
app.ssh_server = await start_ssh_server(app,app.ssh_host,app.ssh_port)
asyncio.create_task(app.ssh_server.wait_closed())
if app.ssh_server:
asyncio.create_task(app.ssh_server.wait_closed())
async def prepare_asyncio(self, app):
# app.loop = asyncio.get_running_loop()

View File

@ -16,4 +16,5 @@ class DriveItemService(BaseService):
if await self.save(model):
return model
errors = await model.errors
print("XXXXXXXXXX")
raise Exception(f"Failed to create drive item: {errors}.")

View File

@ -1,6 +1,7 @@
from snek.model.user import UserModel
from snek.system.service import BaseService
from datetime import datetime
import json
class SocketService(BaseService):
@ -10,6 +11,7 @@ class SocketService(BaseService):
self.is_connected = True
self.user = user
async def send_json(self, data):
if not self.is_connected:
return False
@ -33,7 +35,8 @@ class SocketService(BaseService):
self.sockets = set()
self.users = {}
self.subscriptions = {}
self.last_update = str(datetime.now())
async def add(self, ws, user_uid):
s = self.Socket(ws, await self.app.services.user.get(uid=user_uid))
self.sockets.add(s)
@ -54,7 +57,11 @@ class SocketService(BaseService):
count += 1
return count
async def broadcast(self, channel_uid, message):
await self._broadcast(channel_uid, message)
async def _broadcast(self, channel_uid, message):
try:
async for user_uid in self.services.channel_member.get_user_uids(
channel_uid

View File

@ -1,7 +1,7 @@
import os
import aiohttp
from aiohttp import web
import git
import shutil
import json
import tempfile
@ -14,6 +14,8 @@ logger = logging.getLogger('git_server')
class GitApplication(web.Application):
def __init__(self, parent=None):
#import git
#globals()['git'] = git
self.parent = parent
super().__init__(client_max_size=1024*1024*1024*5)
self.add_routes([

View File

@ -4,7 +4,6 @@ from pathlib import Path
global _app
def set_app(app):
global _app
_app = app
@ -12,19 +11,11 @@ def set_app(app):
def get_app():
return _app
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[
logging.FileHandler("sftp_server.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
roots = {}
class MySFTPServer(asyncssh.SFTPServer):
class SFTPServer(asyncssh.SFTPServer):
def __init__(self, chan: asyncssh.SSHServerChannel):
self.root = get_app().services.user.get_home_folder_by_username(
@ -35,29 +26,24 @@ class MySFTPServer(asyncssh.SFTPServer):
super().__init__(chan, chroot=self.root)
def map_path(self, path):
# Map client path to local filesystem path
mapped_path = Path(self.root).joinpath(path.lstrip(b"/").decode())
#Path(mapped_path).mkdir(exist_ok=True)
print(mapped_path)
logger.debug(f"Mapping client path {path} to {mapped_path}")
return str(mapped_path).encode()
class MySSHServer(asyncssh.SSHServer):
class SSHServer(asyncssh.SSHServer):
def password_auth_supported(self):
return True
def validate_password(self, username, password):
# Simple in-memory user database
logger.debug(f"Validating credentials for user {username}")
return get_app().services.user.authenticate_sync(username,password)
result = get_app().services.user.authenticate_sync(username,password)
logger.info(f"Validating credentials for user {username}: {result}")
return result
async def start_ssh_server(app,host,port):
set_app(app)
logger.info("Starting SFTP server setup")
# Server host key (generate or load one)
host_key_path = Path("drive") / ".ssh" / "sftp_server_key"
host_key_path.parent.mkdir(exist_ok=True)
try:
@ -72,20 +58,19 @@ async def start_ssh_server(app,host,port):
logger.error(f"Failed to generate or load host key: {e}")
raise
# Start the SSH server with SFTP support
logger.info("Starting SFTP server on localhost:8022")
logger.info(f"Starting SFTP server on 127.0.0.1:{port}")
try:
x = await asyncssh.listen(
host=host,
port=port,
#process_factory=handle_client,
server_host_keys=[key],
server_factory=MySSHServer,
sftp_factory=MySFTPServer
server_factory=SSHServer,
sftp_factory=SFTPServer
)
return x
except Exception as e:
logger.error(f"Failed to start SFTP server: {e}")
raise
logger.warning(f"Failed to start SFTP server. Already running.")
pass

View File

@ -6,7 +6,7 @@ import humanize
from aiohttp import web
from snek.system.view import BaseView
import asyncio
from git import Repo