Update drive.
This commit is contained in:
		
							parent
							
								
									c5c160baae
								
							
						
					
					
						commit
						7b32a7eba4
					
				
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@ -15,7 +15,7 @@ run:
 | 
			
		||||
	$(GUNICORN) -w $(GUNICORN_WORKERS) -k aiohttp.worker.GunicornWebWorker snek.gunicorn:app --bind 0.0.0.0:$(PORT) --reload
 | 
			
		||||
	
 | 
			
		||||
install:
 | 
			
		||||
	python3 -m venv .venv 
 | 
			
		||||
	python3.12 -m venv .venv 
 | 
			
		||||
	$(PIP) install -e .
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,7 @@ from snek.view.search_user import SearchUserView
 | 
			
		||||
from snek.view.avatar import AvatarView
 | 
			
		||||
from snek.system.profiler import profiler_handler
 | 
			
		||||
from snek.view.terminal import TerminalView, TerminalSocketView
 | 
			
		||||
from snek.view.drive import DriveView
 | 
			
		||||
from  concurrent.futures import ThreadPoolExecutor
 | 
			
		||||
SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
 | 
			
		||||
 | 
			
		||||
@ -67,6 +68,13 @@ class Application(BaseApplication):
 | 
			
		||||
        self.jinja2_env.add_extension(EmojiExtension)
 | 
			
		||||
        
 | 
			
		||||
        self.setup_router()
 | 
			
		||||
       
 | 
			
		||||
        self.cache = Cache(self)
 | 
			
		||||
        self.services = get_services(app=self)
 | 
			
		||||
        self.mappers = get_mappers(app=self)
 | 
			
		||||
        self.on_startup.append(self.prepare_database)
 | 
			
		||||
 | 
			
		||||
    async def prepare_database(self,app):
 | 
			
		||||
        self.db.query("PRAGMA journal_mode=WAL")
 | 
			
		||||
        self.db.query("PRAGMA syncnorm=off")
 | 
			
		||||
 | 
			
		||||
@ -80,9 +88,7 @@ class Application(BaseApplication):
 | 
			
		||||
        except:
 | 
			
		||||
            pass 
 | 
			
		||||
 
 | 
			
		||||
        self.cache = Cache(self)
 | 
			
		||||
        self.services = get_services(app=self)
 | 
			
		||||
        self.mappers = get_mappers(app=self)
 | 
			
		||||
        await app.services.drive.prepare_all()
 | 
			
		||||
 | 
			
		||||
    def setup_router(self):
 | 
			
		||||
        self.router.add_get("/", IndexView)
 | 
			
		||||
@ -117,6 +123,8 @@ class Application(BaseApplication):
 | 
			
		||||
        self.router.add_view("/threads.html", ThreadsView)
 | 
			
		||||
        self.router.add_view("/terminal.ws", TerminalSocketView)
 | 
			
		||||
        self.router.add_view("/terminal.html", TerminalView)
 | 
			
		||||
        self.router.add_view("/drive.json", DriveView)
 | 
			
		||||
        self.router.add_view("/drive/{drive}.json", DriveView)
 | 
			
		||||
 | 
			
		||||
        self.add_subapp(
 | 
			
		||||
            "/docs",
 | 
			
		||||
 | 
			
		||||
@ -4,4 +4,10 @@ from snek.system.model import BaseModel,ModelField
 | 
			
		||||
class DriveModel(BaseModel):
 | 
			
		||||
 | 
			
		||||
    user_uid = ModelField(name="user_uid", required=True)
 | 
			
		||||
    name = ModelField(name='name', required=False, type=str) 
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    async def items(self):
 | 
			
		||||
        async for drive_item in self.app.services.drive_item.find(drive_uid=self['uid']):
 | 
			
		||||
            yield drive_item
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
from snek.system.model import BaseModel,ModelField 
 | 
			
		||||
 | 
			
		||||
import mimetypes
 | 
			
		||||
 | 
			
		||||
class DriveItemModel(BaseModel):
 | 
			
		||||
    drive_uid = ModelField(name="drive_uid", required=True,kind=str)
 | 
			
		||||
@ -7,3 +7,12 @@ class DriveItemModel(BaseModel):
 | 
			
		||||
    path = ModelField(name="path", required=True,kind=str)
 | 
			
		||||
    file_type = ModelField(name="file_type", required=True,kind=str) 
 | 
			
		||||
    file_size = ModelField(name="file_size", required=True,kind=int)
 | 
			
		||||
    
 | 
			
		||||
    @property
 | 
			
		||||
    def extension(self):
 | 
			
		||||
        return self['name'].split('.')[-1]
 | 
			
		||||
    
 | 
			
		||||
    @property 
 | 
			
		||||
    def mime_type(self):
 | 
			
		||||
        mimetype,_ = mimetypes.guess_type(self['name'])
 | 
			
		||||
        return mimetype 
 | 
			
		||||
 | 
			
		||||
@ -5,17 +5,75 @@ class DriveService(BaseService):
 | 
			
		||||
    
 | 
			
		||||
    mapper_name = "drive"
 | 
			
		||||
 | 
			
		||||
    async def get_by_user(self, user_uid):
 | 
			
		||||
        drives = [] 
 | 
			
		||||
        async for model in self.find(user_uid=user_uid):
 | 
			
		||||
            drives.append(model)
 | 
			
		||||
        return drives 
 | 
			
		||||
    EXTENSIONS_PICTURES = ["jpg","jpeg","png","gif","svg","webp","tiff"]
 | 
			
		||||
    EXTENSIONS_VIDEOS = ["mp4","m4v","mov","wmv","webm","mkv","mpg","mpeg","avi","ogv","ogg","flv","3gp","3g2"]
 | 
			
		||||
    EXTENSIONS_ARCHIVES = ["zip","rar","7z","tar","tar.gz","tar.xz","tar.bz2","tar.lzma","tar.lz"]
 | 
			
		||||
    EXTENSIONS_AUDIO = ["mp3","wav","ogg","flac","m4a","wma","aac","opus","aiff","au","mid","midi"]
 | 
			
		||||
    EXTENSIONS_DOCS = ["pdf","doc","docx","xls","xlsx","ppt","pptx","txt","md","json","csv","xml","html","css","js","py","sql","rs","toml","yml","yaml","ini","conf","config","log","csv","tsv","java","cs","csproj","scss","less","sass","json","lock","lock.json","jsonl"]
 | 
			
		||||
 | 
			
		||||
    async def get_drive_name_by_extension(self, extension):
 | 
			
		||||
        if extension.startswith("."):
 | 
			
		||||
            extension = extension[1:]
 | 
			
		||||
        if extension in self.EXTENSIONS_PICTURES:
 | 
			
		||||
            return "Pictures"
 | 
			
		||||
        if extension in self.EXTENSIONS_VIDEOS:
 | 
			
		||||
            return "Videos"
 | 
			
		||||
        if extension in self.EXTENSIONS_ARCHIVES:
 | 
			
		||||
            return "Archives"
 | 
			
		||||
        if extension in self.EXTENSIONS_AUDIO:
 | 
			
		||||
            return "Audio"
 | 
			
		||||
        if extension in self.EXTENSIONS_DOCS:
 | 
			
		||||
            return "Documents"
 | 
			
		||||
        return "My Drive"
 | 
			
		||||
 | 
			
		||||
    async def get_drive_by_extension(self,user_uid, extension):
 | 
			
		||||
        name = await self.get_drive_name_by_extension(extension)
 | 
			
		||||
        return await self.get_or_create(user_uid=user_uid,name=name)
 | 
			
		||||
 | 
			
		||||
    async def get_by_user(self, user_uid,name=None):
 | 
			
		||||
        kwargs = dict(
 | 
			
		||||
            user_uid = user_uid
 | 
			
		||||
        )
 | 
			
		||||
        async for model in self.find(**kwargs):
 | 
			
		||||
            if not name:
 | 
			
		||||
                yield model 
 | 
			
		||||
            elif model['name'] == name:
 | 
			
		||||
                yield model
 | 
			
		||||
            elif not model['name'] and name == 'My Drive':
 | 
			
		||||
                model['name'] = 'My Drive'
 | 
			
		||||
                await self.save(model)
 | 
			
		||||
                yield model 
 | 
			
		||||
 | 
			
		||||
    async def get_or_create(self, user_uid,name=None,extensions=None):
 | 
			
		||||
        kwargs = dict(user_uid=user_uid)
 | 
			
		||||
        if name:
 | 
			
		||||
            kwargs['name'] = name
 | 
			
		||||
        async for model in self.get_by_user(**kwargs):
 | 
			
		||||
            return model  
 | 
			
		||||
 | 
			
		||||
    async def get_or_create(self, user_uid):
 | 
			
		||||
        drives = await self.get_by_user(user_uid=user_uid)
 | 
			
		||||
        if len(drives) == 0:
 | 
			
		||||
        model = await self.new()
 | 
			
		||||
        model['user_uid'] = user_uid
 | 
			
		||||
        model['name'] = name 
 | 
			
		||||
        await self.save(model)
 | 
			
		||||
        return model 
 | 
			
		||||
        return drives[0]
 | 
			
		||||
 | 
			
		||||
    async def prepare_default_drives(self):
 | 
			
		||||
        async for drive_item in self.services.drive_item.find():
 | 
			
		||||
            extension = drive_item.extension
 | 
			
		||||
            drive = await self.get_drive_by_extension(drive_item['user_uid'],extension)
 | 
			
		||||
            if not drive_item['drive_uid'] == drive['uid']:
 | 
			
		||||
                drive_item['drive_uid'] = drive['uid']
 | 
			
		||||
                await self.services.drive_item.save(drive_item)
 | 
			
		||||
            
 | 
			
		||||
    async def prepare_default_drives_for_user(self, user_uid):
 | 
			
		||||
        await self.get_or_create(user_uid=user_uid,name="My Drive")
 | 
			
		||||
        await self.get_or_create(user_uid=user_uid,name="Shared Drive")
 | 
			
		||||
        await self.get_or_create(user_uid=user_uid,name="Pictures")
 | 
			
		||||
        await self.get_or_create(user_uid=user_uid,name="Videos")
 | 
			
		||||
        await self.get_or_create(user_uid=user_uid,name="Archives")
 | 
			
		||||
        await self.get_or_create(user_uid=user_uid,name="Documents")
 | 
			
		||||
 | 
			
		||||
    async def prepare_all(self):
 | 
			
		||||
        await self.prepare_default_drives()
 | 
			
		||||
        async for user in self.services.user.find():
 | 
			
		||||
            await self.prepare_default_drives_for_user(user['uid']) 
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ class DriveItemService(BaseService):
 | 
			
		||||
        model['drive_uid'] = drive_uid 
 | 
			
		||||
        model['name'] = name 
 | 
			
		||||
        model['path'] = str(path) 
 | 
			
		||||
        model['extension'] = str(name).split(".")[-1]
 | 
			
		||||
        model['file_type'] = type_ 
 | 
			
		||||
        model['file_size'] = size
 | 
			
		||||
        if await self.save(model):
 | 
			
		||||
 | 
			
		||||
@ -13,20 +13,66 @@ commands = {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class TerminalSession:
 | 
			
		||||
    
 | 
			
		||||
    async def ensure_process(self):
 | 
			
		||||
        if self.process:
 | 
			
		||||
            return
 | 
			
		||||
        self.process = await asyncio.create_subprocess_exec(
 | 
			
		||||
            *self.command.split(" "),
 | 
			
		||||
            stdin=self.slave,
 | 
			
		||||
            stdout=self.slave,
 | 
			
		||||
            stderr=self.slave,bufsize=0,
 | 
			
		||||
            universal_newlines=True
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __init__(self,command):
 | 
			
		||||
        self.master, self.slave = pty.openpty()
 | 
			
		||||
        self.sockets =[]
 | 
			
		||||
        self.buffer = b''
 | 
			
		||||
        self.process = subprocess.Popen(
 | 
			
		||||
            command.split(" "),
 | 
			
		||||
            stdin=self.slave,
 | 
			
		||||
            stdout=self.slave,
 | 
			
		||||
            stderr=self.slave,
 | 
			
		||||
            bufsize=0,
 | 
			
		||||
            universal_newlines=True
 | 
			
		||||
        )
 | 
			
		||||
        self.process = None 
 | 
			
		||||
 | 
			
		||||
        #self.process = subprocess.Popen(
 | 
			
		||||
        #    command.split(" "),
 | 
			
		||||
        #    stdin=self.slave,
 | 
			
		||||
        #    stdout=self.slave,
 | 
			
		||||
        #    stderr=self.slave,
 | 
			
		||||
        #    bufsize=0,
 | 
			
		||||
        #    universal_newlines=True
 | 
			
		||||
        #)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    async def read_output(self, ws):
 | 
			
		||||
        await self.ensure_process()
 | 
			
		||||
        self.sockets.append(ws)
 | 
			
		||||
        if len(self.sockets) > 1:
 | 
			
		||||
            start = self.buffer.index(b'\n')
 | 
			
		||||
            await ws.send_bytes(self.buffer[start:])
 | 
			
		||||
            return 
 | 
			
		||||
        while True:
 | 
			
		||||
            try:
 | 
			
		||||
                async for data in self.process.stdout:
 | 
			
		||||
                    if not data:
 | 
			
		||||
                        break
 | 
			
		||||
                    self.buffer += data
 | 
			
		||||
                    if len(self.buffer) > 10000:
 | 
			
		||||
                        self.buffer = self.buffer[:-10000]
 | 
			
		||||
                    try:
 | 
			
		||||
                        for ws in self.sockets: await ws.send_bytes(data)  # Send raw bytes for ANSI support
 | 
			
		||||
                    except:
 | 
			
		||||
                        self.sockets.remove(ws)
 | 
			
		||||
            except:
 | 
			
		||||
                print("Terminating process")
 | 
			
		||||
                self.process.terminate()
 | 
			
		||||
                print("Terminated process")
 | 
			
		||||
                for ws in self.sockets:
 | 
			
		||||
                    try:
 | 
			
		||||
                        await ws.close()
 | 
			
		||||
                    except Exception:
 | 
			
		||||
                        pass
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
    async def read_outputa(self, ws):
 | 
			
		||||
        loop = asyncio.get_event_loop()
 | 
			
		||||
        self.sockets.append(ws)
 | 
			
		||||
        if len(self.sockets) > 1:
 | 
			
		||||
@ -57,6 +103,7 @@ class TerminalSession:
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
    async def write_input(self, data):
 | 
			
		||||
        await self.ensure_process()
 | 
			
		||||
        os.write(self.master, data.encode())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								src/snek/view/drive.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/snek/view/drive.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
from snek.system.view import BaseView
 | 
			
		||||
from aiohttp import web
 | 
			
		||||
 | 
			
		||||
class DriveView(BaseView):
 | 
			
		||||
 | 
			
		||||
    login_required = True
 | 
			
		||||
 | 
			
		||||
    async def get(self):
 | 
			
		||||
 | 
			
		||||
        drive_uid = self.request.match_info.get("drive")
 | 
			
		||||
 | 
			
		||||
        if drive_uid:
 | 
			
		||||
            drive = await self.services.drive.get(uid=drive_uid)
 | 
			
		||||
            drive_items = []
 | 
			
		||||
            async for item in drive.items:
 | 
			
		||||
                drive_items.append(item.record)
 | 
			
		||||
            return web.json_response(drive_items)
 | 
			
		||||
 | 
			
		||||
        user = await self.services.user.get(uid=self.session.get("uid"))
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        drives = []
 | 
			
		||||
        async for drive in self.services.drive.get_by_user(user['uid']):
 | 
			
		||||
            record = drive.record
 | 
			
		||||
            record['items'] = []
 | 
			
		||||
            async for item in drive.items:
 | 
			
		||||
                record['items'].append(item.record)
 | 
			
		||||
            drives.append(record)
 | 
			
		||||
        
 | 
			
		||||
        return web.json_response(drives)
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user