Progress.

This commit is contained in:
retoor 2025-01-26 22:48:58 +01:00
parent f25feeeca3
commit 488afdcc74
9 changed files with 190 additions and 31 deletions

View File

@ -22,6 +22,7 @@ from snek.view.index import IndexView
from snek.view.login import LoginView
from snek.view.logout import LogoutView
from snek.view.register import RegisterView
from snek.view.rpc import RPCView
from snek.view.status import StatusView
from snek.view.web import WebView
@ -77,7 +78,7 @@ class Application(BaseApplication):
self.router.add_view("/register.json", RegisterView)
self.router.add_get("/http-get", self.handle_http_get)
self.router.add_get("/http-photo", self.handle_http_photo)
self.router.add_get("/rpc.ws",RPCView)
self.add_subapp(
"/docs",
DocsApplication(path=pathlib.Path(__file__).parent.joinpath("docs")),

View File

@ -0,0 +1,9 @@
from snek.model.notification import NotificationModel
from snek.system.mapper import BaseMapper
class NotificationMapper(BaseMapper):
table_name = "notification"
model_class = NotificationModel

View File

@ -2,6 +2,9 @@ import functools
from snek.service.channel import ChannelService
from snek.service.channel_member import ChannelMemberService
from snek.service.channel_message import ChannelMessageService
from snek.service.chat import ChatService
from snek.service.socket import SocketService
from snek.service.user import UserService
from snek.system.object import Object
@ -13,6 +16,9 @@ def get_services(app):
"user": UserService(app=app),
"channel_member": ChannelMemberService(app=app),
"channel": ChannelService(app=app),
"channel_message": ChannelMessageService(app=app),
"chat": ChatService(app=app),
"socket": SocketService(app=app),
}
)

View File

@ -28,6 +28,7 @@ class ChannelMemberService(BaseService):
model["is_read_only"] = is_read_only
model["is_muted"] = is_muted
model["is_banned"] = is_banned
print(model.record,flush=True)
if await self.save(model):
return model
raise Exception(f"Failed to create channel member: {model.errors}.")

View File

@ -1,6 +1,6 @@
class Message {
/*class Message {
uid = null
author = null
avatar = null
@ -38,7 +38,7 @@ class Message {
}
return result
}
}
}*/
class Messages {
@ -204,17 +204,153 @@ class Chat extends EventHandler {
}
class App {
rooms = []
class Socket extends EventHandler {
ws = null
isConnected = null
isConnecting = null
connectPromises = []
constructor() {
super()
this.ensureConnection()
}
_camelToSnake(str) {
return str
.replace(/([a-z])([A-Z])/g, '$1_$2')
.toLowerCase();
}
get client() {
const me = this
const proxy = new Proxy(
{},
{
get(target, prop) {
return (...args) => {
let functionName = me._camelToSnake(prop)
return me.call(functionName, ...args);
};
},
}
);
return proxy
}
ensureConnection(){
return this.connect()
}
generateUniqueId() {
return 'id-' + Math.random().toString(36).substr(2, 9);
}
connect(){
const me = this
if(!this.isConnected && !this.isConnecting){
this.isConnecting = true
}else if (this.isConnecting){
return new Promise((resolve,reject)=>{
me.connectPromises.push(resolve)
})
}else if(this.isConnected){
return new Promise((resolve,reject)=>{
resolve(me)
})
}
return new Promise((resolve,reject)=>{
me.connectPromises.push(resolve)
const ws = new WebSocket("ws://localhost:8081/rpc.ws")
ws.onopen = (event) => {
me.ws = ws
me.isConnected = true
me.isConnecting = false
ws.onmessage = (event) => {
me.onData(JSON.parse(event.data))
}
ws.onclose = (event) =>{
me.onClose()
}
me.connectPromises.forEach(resolve=>{
resolve(me)
})
}
})
}
onData(data){
console.debug("Data received",data)
if(data.callId){
this.emit(data.callId, data.data)
}
if(data.channel_uid){
this.emit(data.channel_uid,data.data)
this.emit("channel-message",data)
}
}
async sendJson(data){
return await this.connect().then((api)=>{
api.ws.send(JSON.stringify(data))
})
}
async call(method,...args){
const call= {
callId: this.generateUniqueId(),
method: method,
args: args
}
const me = this
return new Promise(async(resolve,reject)=>{
me.addEventListener(call.callId,(data)=>{
resolve(data)
})
await me.sendJson(call)
})
}
onClose(){
console.info("Connection lost. Reconnecting.")
this.isConnected = false
this.isConnecting = false
this.ensureConnection().then(()=>{
console.info("Reconnected.")
})
}
}
class App extends EventHandler {
rooms = []
rest = rest
ws = null
rpc = null
constructor() {
super()
this.rooms.push(new Room("General"))
this.ws = new Socket()
this.rpc = this.ws.client
const me = this
this.ws.addEventListener("channel-message", (data) => {
console.debug("App channel message!",data)
me.emit(data.channel_uid,data)
})
}
async post(url, data){
async benchMark(times) {
if(!times)
times = 100
let promises = []
const me = this
for(let i = 0; i < times; i++){
promises.push(this.rpc.getChannels().then(channels=>{
channels.forEach(channel=>{
me.rpc.sendMessage(channel.uid,`Haha ${i}`).then(data=>{
console.info(data)
})
})
}))
}
return await Promise.all(promises)
}
}
}
const app = new App()

View File

@ -109,6 +109,12 @@ main {
background: #1a1a1a;
}
.message-list-manager {
flex: 1;
overflow-y: auto;
background: #1a1a1a;
}
.chat-messages .message {
display: flex;
align-items: flex-start;

View File

@ -19,6 +19,10 @@ class BaseView(web.View):
@property
def db(self):
return self.app.db
@property
def services(self):
return self.app.services
async def json_response(self, data, **kwargs):
return web.json_response(data, **kwargs)

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{% endblock %}</title>
<script src="/app.js"></script>
<script src="/message-list.js"></script>
<style>{{ highlight_styles }}</style>
<link rel="stylesheet" href="/style.css">
<script src="/fancy-button.js"></script>

View File

@ -5,6 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snek</title>
<script src="/app.js"></script>
<script src="/models.js"></script>
<script src="/message-list.js"></script>
<script src="/message-list-manager.js"></script>
<link rel="stylesheet" href="base.css">
</head>
<body>
@ -31,31 +34,23 @@
<div class="chat-header">
<h2>General</h2>
</div>
<div class="chat-messages">
<div class="message">
<div class="avatar">A</div>
<div class="message-content">
<div class="author">Alice</div>
<div class="text">Hello, everyone!</div>
<div class="time">10:45 AM</div>
</div>
</div>
<html-frame class="html-frame" url="/register"></html-frame>
<div class="message">
<div class="avatar">B</div>
<div class="message-content">
<div class="author">Bob</div>
<div class="text">Hi Alice! How are you?</div>
<div class="time">10:46 AM</div>
</div>
</div>
</div>
<message-list-manager class="message-list-manager"></message-list-manager>
<div class="chat-input">
<textarea placeholder="Type a message..." rows="2"></textarea>
<button>Send</button>
</div>
</section>
</main>
<script>
document.addEventListener("DOMContentLoaded",()=>{
setTimeout(()=>{
app.benchMark(3).then(result=>{
console.info("Benchmarked")
})
},1000)
})
</script>
</body>
</html>