Added online status
This commit is contained in:
		
							parent
							
								
									49c0f932ab
								
							
						
					
					
						commit
						54c40c6b85
					
				| @ -29,3 +29,5 @@ class UserModel(BaseModel): | |||||||
|         regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", |         regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", | ||||||
|     ) |     ) | ||||||
|     password = ModelField(name="password", required=True, min_length=1) |     password = ModelField(name="password", required=True, min_length=1) | ||||||
|  | 
 | ||||||
|  |     last_ping = ModelField(name="last_ping", required=False, kind=str) | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| from snek.system.service import BaseService | from snek.system.service import BaseService | ||||||
|  | from datetime import datetime  | ||||||
| 
 | 
 | ||||||
|  | from snek.system.model import now  | ||||||
| 
 | 
 | ||||||
| class ChannelService(BaseService): | class ChannelService(BaseService): | ||||||
|     mapper_name = "channel" |     mapper_name = "channel" | ||||||
| @ -29,6 +31,25 @@ class ChannelService(BaseService): | |||||||
|             return model |             return model | ||||||
|         raise Exception(f"Failed to create channel: {model.errors}.") |         raise Exception(f"Failed to create channel: {model.errors}.") | ||||||
| 
 | 
 | ||||||
|  |     async def get_users(self, channel_uid): | ||||||
|  |         users = [] | ||||||
|  |         async for channel_member in self.services.channel_member.find( | ||||||
|  |             channel_uid=channel_uid, | ||||||
|  |             is_banned=False, | ||||||
|  |             is_muted=False, | ||||||
|  |             deleted_at=None, | ||||||
|  |         ): | ||||||
|  |             yield await self.services.user.get(uid=channel_member["user_uid"]) | ||||||
|  | 
 | ||||||
|  |     async def get_online_users(self, channel_uid): | ||||||
|  |         users = [] | ||||||
|  |         async for user in self.get_users(channel_uid): | ||||||
|  |             if not user["last_ping"]: | ||||||
|  |                 continue | ||||||
|  | 
 | ||||||
|  |             if (datetime.fromisoformat(now()) - datetime.fromisoformat(user["last_ping"])).total_seconds() < 30: | ||||||
|  |                 yield user  | ||||||
|  | 
 | ||||||
|     async def ensure_public_channel(self, created_by_uid): |     async def ensure_public_channel(self, created_by_uid): | ||||||
|         model = await self.get(is_listed=True, tag="public") |         model = await self.get(is_listed=True, tag="public") | ||||||
|         is_moderator = False |         is_moderator = False | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ class UserService(BaseService): | |||||||
|             user['color'] = await self.services.util.random_light_hex_color() |             user['color'] = await self.services.util.random_light_hex_color() | ||||||
|         return await super().save(user) |         return await super().save(user) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     async def register(self, email, username, password): |     async def register(self, email, username, password): | ||||||
|         if await self.exists(username=username): |         if await self.exists(username=username): | ||||||
|             raise Exception("User already exists.") |             raise Exception("User already exists.") | ||||||
|  | |||||||
| @ -206,11 +206,14 @@ class Socket extends EventHandler { | |||||||
|                 ws.onerror = () => { |                 ws.onerror = () => { | ||||||
|                     this.onClose(); |                     this.onClose(); | ||||||
|                 }; |                 }; | ||||||
|  |                 this.onConnect() | ||||||
|                 this.connectPromises.forEach(resolver => resolver(this)); |                 this.connectPromises.forEach(resolver => resolver(this)); | ||||||
|             }; |             }; | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 |     onConnect(){ | ||||||
|  |         this.emit("connected") | ||||||
|  |     } | ||||||
|     onData(data) { |     onData(data) { | ||||||
|         if (data.success !== undefined && !data.success) { |         if (data.success !== undefined && !data.success) { | ||||||
|             console.error(data); |             console.error(data); | ||||||
| @ -282,12 +285,31 @@ class App extends EventHandler { | |||||||
|     audio = null; |     audio = null; | ||||||
|     user = {}; |     user = {}; | ||||||
| 
 | 
 | ||||||
|  |     async ping(...args) { | ||||||
|  |         if(this.is_pinging)return false  | ||||||
|  |         this.is_pinging = true | ||||||
|  |         await this.rpc.ping(...args); | ||||||
|  |         this.is_pinging = false | ||||||
|  |     } | ||||||
|  |     async forcePing(...arg) { | ||||||
|  |         await this.rpc.ping(...args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
|         this.ws = new Socket(); |         this.ws = new Socket(); | ||||||
|         this.rpc = this.ws.client; |         this.rpc = this.ws.client; | ||||||
|         this.audio = new NotificationAudio(500); |         this.audio = new NotificationAudio(500); | ||||||
|  |         this.is_pinging = false  | ||||||
|  |         this.ping_interval = setInterval(()=>{ | ||||||
|  |             this.ping("active") | ||||||
|  |         }, 15000) | ||||||
|  |          | ||||||
|  | 
 | ||||||
|         const me = this  |         const me = this  | ||||||
|  |         this.ws.addEventListener("connected", (data)=> { | ||||||
|  |             this.ping("online") | ||||||
|  |         }) | ||||||
|         this.ws.addEventListener("channel-message", (data) => { |         this.ws.addEventListener("channel-message", (data) => { | ||||||
|             me.emit("channel-message", data); |             me.emit("channel-message", data); | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ from aiohttp import web | |||||||
| from snek.system.view import BaseView | from snek.system.view import BaseView | ||||||
| import traceback | import traceback | ||||||
| import json | import json | ||||||
|  | from snek.system.model import now  | ||||||
| 
 | 
 | ||||||
| class RPCView(BaseView): | class RPCView(BaseView): | ||||||
| 
 | 
 | ||||||
| @ -134,7 +135,23 @@ class RPCView(BaseView): | |||||||
|         async def _send_json(self, obj): |         async def _send_json(self, obj): | ||||||
|             await self.ws.send_str(json.dumps(obj, default=str)) |             await self.ws.send_str(json.dumps(obj, default=str)) | ||||||
|      |      | ||||||
|         async def call_ping(self, callId, *args): | 
 | ||||||
|  |         async def get_online_users(self, channel_uid): | ||||||
|  |             self._require_login() | ||||||
|  |              | ||||||
|  |             return [dict(uid=record['uid'],username=record['username'], nick=record['nick']) async for record in self.services.channel.get_online_users(channel_uid)] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         async def get_users(self, channel_uid): | ||||||
|  |             self._require_login() | ||||||
|  | 
 | ||||||
|  |             return [dict(uid=record['uid'],username=record['username'], nick=record['nick']) async for record in self.services.channel.get_users(channel_uid)] | ||||||
|  | 
 | ||||||
|  |         async def ping(self, callId, *args): | ||||||
|  |             if self.user_uid: | ||||||
|  |                 user = await self.services.user.get(uid=self.user_uid) | ||||||
|  |                 user['last_ping'] = now() | ||||||
|  |                 await self.services.user.save(user) | ||||||
|             return {"pong": args} |             return {"pong": args} | ||||||
| 
 | 
 | ||||||
|     async def get(self): |     async def get(self): | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user