diff --git a/server/src/client.ts b/server/src/client.ts index 698e3de..b0dec7d 100644 --- a/server/src/client.ts +++ b/server/src/client.ts @@ -78,8 +78,12 @@ export class Client extends EventEmitter { username = uo + i++; } while (this.room.clients.some(u => u.username === username)) } + if (!this.room.agents.some(a => a.filename === joinMsg.data.agent)) { + this.socket.close(); + return; + } this.username = username; - this.agent = htmlentities.encode(joinMsg.data.agent); + this.agent = joinMsg.data.agent; this.emit('join'); break; } diff --git a/server/src/index.ts b/server/src/index.ts index 29e9e8b..30f9443 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -73,15 +73,10 @@ app.register(FastifyStatic, { }); app.get("/api/agents", (req, res) => { - return config.agents.map(a => { - return { - url: `/api/agents/${a.filename}`, - name: a.friendlyName - } - }); + return config.agents; }); -let room = new MSAgentChatRoom(config.chat, tts); +let room = new MSAgentChatRoom(config.chat, config.agents, tts); app.register(async app => { app.get("/api/socket", {websocket: true}, (socket, req) => { diff --git a/server/src/room.ts b/server/src/room.ts index c9d2266..3d6ed1e 100644 --- a/server/src/room.ts +++ b/server/src/room.ts @@ -1,16 +1,18 @@ import { MSAgentAddUserMessage, MSAgentChatMessage, MSAgentInitMessage, MSAgentProtocolMessage, MSAgentProtocolMessageType, MSAgentRemoveUserMessage } from "@msagent-chat/protocol"; import { Client } from "./client.js"; import { TTSClient } from "./tts.js"; -import { ChatConfig } from "./config.js"; +import { AgentConfig, ChatConfig } from "./config.js"; import * as htmlentities from 'html-entities'; export class MSAgentChatRoom { + agents: AgentConfig[]; clients: Client[]; tts: TTSClient | null; msgId : number = 0; config: ChatConfig; - constructor(config: ChatConfig, tts: TTSClient | null) { + constructor(config: ChatConfig, agents: AgentConfig[], tts: TTSClient | null) { + this.agents = agents; this.clients = []; this.config = config; this.tts = tts; diff --git a/webapp/src/html/index.html b/webapp/src/html/index.html index 1cdbd41..0113958 100644 --- a/webapp/src/html/index.html +++ b/webapp/src/html/index.html @@ -32,6 +32,9 @@
+
diff --git a/webapp/src/ts/client.ts b/webapp/src/ts/client.ts index 60817d7..6144620 100644 --- a/webapp/src/ts/client.ts +++ b/webapp/src/ts/client.ts @@ -1,6 +1,7 @@ import { createNanoEvents, Emitter, Unsubscribe } from 'nanoevents'; import { MSAgentAddUserMessage, MSAgentChatMessage, MSAgentInitMessage, MSAgentJoinMessage, MSAgentProtocolMessage, MSAgentProtocolMessageType, MSAgentRemoveUserMessage, MSAgentTalkMessage } from '@msagent-chat/protocol'; import { User } from './user'; +import { agentCreateCharacterFromUrl } from '@msagent-chat/msagent.js'; export interface MSAgentClientEvents { close: () => void; @@ -10,6 +11,11 @@ export interface MSAgentClientEvents { chat: (user: User, msg: string) => void; } +export interface APIAgentInfo { + friendlyName: string; + filename: string; +} + export class MSAgentClient { private url: string; private socket: WebSocket | null; @@ -19,10 +25,12 @@ export class MSAgentClient { private charlimit: number = 0; private username: string | null = null; + private agentContainer: HTMLElement; private agent: string | null = null; - constructor(url: string) { + constructor(url: string, agentContainer: HTMLElement) { this.url = url; + this.agentContainer = agentContainer; this.socket = null; this.events = createNanoEvents(); this.users = []; @@ -32,6 +40,11 @@ export class MSAgentClient { return this.events.on(event, callback); } + async getAgents() { + let res = await fetch(this.url + "/api/agents"); + return await res.json() as APIAgentInfo[]; + } + connect(): Promise { return new Promise(res => { let url = new URL(this.url); @@ -104,7 +117,7 @@ export class MSAgentClient { return this.charlimit; } - private handleMessage(data: string) { + private async handleMessage(data: string) { let msg: MSAgentProtocolMessage; try { msg = JSON.parse(data); @@ -118,13 +131,22 @@ export class MSAgentClient { this.username = initMsg.data.username; this.agent = initMsg.data.agent; this.charlimit = initMsg.data.charlimit; - this.users.push(...initMsg.data.users.map(u => new User(u.username, u.agent))); + for (let _user of initMsg.data.users) { + let agent = await agentCreateCharacterFromUrl(this.url + "/api/agents/" + _user.agent); + agent.addToDom(this.agentContainer); + agent.show(); + let user = new User(_user.username, agent); + this.users.push(user); + } this.events.emit('join'); break; } case MSAgentProtocolMessageType.AddUser: { - let addUserMsg = msg as MSAgentAddUserMessage - let user = new User(addUserMsg.data.username, addUserMsg.data.agent); + let addUserMsg = msg as MSAgentAddUserMessage; + let agent = await agentCreateCharacterFromUrl(this.url + "/api/agents/" + addUserMsg.data.agent); + agent.addToDom(this.agentContainer); + agent.show(); + let user = new User(addUserMsg.data.username, agent); this.users.push(user); this.events.emit('adduser', user); break; @@ -133,6 +155,7 @@ export class MSAgentClient { let remUserMsg = msg as MSAgentRemoveUserMessage; let user = this.users.find(u => u.username === remUserMsg.data.username); if (!user) return; + user.agent.hide(true); if (this.playingAudio.has(user!.username)) { this.playingAudio.delete(user!.username); } diff --git a/webapp/src/ts/main.ts b/webapp/src/ts/main.ts index 514c490..94c84ab 100644 --- a/webapp/src/ts/main.ts +++ b/webapp/src/ts/main.ts @@ -2,19 +2,21 @@ import { MSWindow, MSWindowStartPosition } from "./MSWindow.js"; import { agentInit } from "@msagent-chat/msagent.js"; import { MSAgentClient } from "./client.js"; -let Room : MSAgentClient | null = null; const elements = { logonView: document.getElementById("logonView") as HTMLDivElement, logonWindow: document.getElementById("logonWindow") as HTMLDivElement, logonForm: document.getElementById("logonForm") as HTMLFormElement, logonUsername: document.getElementById("logonUsername") as HTMLInputElement, + agentSelect: document.getElementById("agentSelect") as HTMLSelectElement, chatView: document.getElementById("chatView") as HTMLDivElement, chatInput: document.getElementById("chatInput") as HTMLInputElement, chatSendBtn: document.getElementById("chatSendBtn") as HTMLButtonElement } +let Room : MSAgentClient = new MSAgentClient(`${window.location.protocol}//${window.location.host}`, elements.chatView); + let logonWindow = new MSWindow(elements.logonWindow, { width: 500, height: 275, @@ -39,9 +41,12 @@ elements.chatSendBtn.addEventListener('click', () => { }); async function connectToRoom() { - Room = new MSAgentClient(`${window.location.protocol}//${window.location.host}`); + if (!elements.agentSelect.value) { + alert("Please select an agent."); + return; + } await Room.connect(); - await Room.join(elements.logonUsername.value, "test"); + await Room.join(elements.logonUsername.value, elements.agentSelect.value); elements.chatInput.maxLength = Room.getCharlimit(); logonWindow.hide(); elements.logonView.style.display = "none"; @@ -50,6 +55,12 @@ async function connectToRoom() { document.addEventListener('DOMContentLoaded', async () => { await agentInit(); + for (const agent of await Room.getAgents()) { + let option = document.createElement("option"); + option.innerText = agent.friendlyName; + option.value = agent.filename; + elements.agentSelect.appendChild(option); + } }); function talk() { diff --git a/webapp/src/ts/user.ts b/webapp/src/ts/user.ts index 6b5f588..58e6dc3 100644 --- a/webapp/src/ts/user.ts +++ b/webapp/src/ts/user.ts @@ -1,8 +1,10 @@ +import { Agent } from "@msagent-chat/msagent.js"; + export class User { username: string; - agent: string; + agent: Agent - constructor(username: string, agent: string) { + constructor(username: string, agent: Agent) { this.username = username; this.agent = agent; }