KI-AGENT: Nativen Matrix-Chat in FEDEO starten
This commit is contained in:
@@ -11,6 +11,17 @@ type MatrixErrorResponse = {
|
||||
error?: string
|
||||
}
|
||||
|
||||
type MatrixRoomEvent = {
|
||||
event_id: string
|
||||
sender: string
|
||||
origin_server_ts: number
|
||||
type: string
|
||||
content?: {
|
||||
body?: string
|
||||
msgtype?: string
|
||||
}
|
||||
}
|
||||
|
||||
const trimTrailingSlash = (value: string) => value.replace(/\/+$/, "")
|
||||
const readLocalDevRegistrationSharedSecret = () => {
|
||||
if (process.env.NODE_ENV === "production") return ""
|
||||
@@ -277,6 +288,30 @@ export function matrixService(server: FastifyInstance) {
|
||||
})
|
||||
}
|
||||
|
||||
const createAccessTokenForUser = async (userId: string, tenantId: number | null) => {
|
||||
await provisionCurrentUser(userId, tenantId)
|
||||
|
||||
const matrixUserId = await matrixUserIdForUser(userId, tenantId)
|
||||
const serviceLogin = await ensureServiceAccessToken()
|
||||
const validUntilMs = Date.now() + 10 * 60 * 1000
|
||||
|
||||
const login = await requestMatrixJson<{ access_token: string }>(
|
||||
`/_synapse/admin/v1/users/${encodeURIComponent(matrixUserId)}/login`,
|
||||
serviceLogin.access_token,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ valid_until_ms: validUntilMs }),
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
accessToken: login.access_token,
|
||||
matrixUserId,
|
||||
validUntilMs,
|
||||
}
|
||||
}
|
||||
|
||||
const getStatus = async () => {
|
||||
const configured = Boolean(homeserverUrl() && serverName())
|
||||
|
||||
@@ -607,6 +642,118 @@ export function matrixService(server: FastifyInstance) {
|
||||
}
|
||||
}
|
||||
|
||||
const ensureCurrentUserJoinedRoom = async (
|
||||
userId: string,
|
||||
tenantId: number | null,
|
||||
room: { roomId: string, alias: string }
|
||||
) => {
|
||||
const session = await createAccessTokenForUser(userId, tenantId)
|
||||
|
||||
try {
|
||||
await requestMatrixJson(
|
||||
`/_matrix/client/v3/join/${encodeURIComponent(room.roomId || room.alias)}`,
|
||||
session.accessToken,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({}),
|
||||
}
|
||||
)
|
||||
} catch (err: any) {
|
||||
if (err.errcode !== "M_FORBIDDEN" && err.errcode !== "M_UNKNOWN") {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
const getGeneralRoomMessages = async (userId: string, tenantId: number | null) => {
|
||||
const room = await provisionTenantRoom(userId, tenantId, {
|
||||
key: "allgemein",
|
||||
name: "Allgemeiner Chat",
|
||||
})
|
||||
|
||||
const session = await ensureCurrentUserJoinedRoom(userId, tenantId, {
|
||||
roomId: room.roomId,
|
||||
alias: room.alias,
|
||||
})
|
||||
|
||||
const response = await requestMatrixJson<{
|
||||
chunk: MatrixRoomEvent[]
|
||||
start?: string
|
||||
end?: string
|
||||
}>(
|
||||
`/_matrix/client/v3/rooms/${encodeURIComponent(room.roomId)}/messages?dir=b&limit=50`,
|
||||
session.accessToken
|
||||
)
|
||||
|
||||
return {
|
||||
roomId: room.roomId,
|
||||
alias: room.alias,
|
||||
matrixUserId: session.matrixUserId,
|
||||
messages: response.chunk
|
||||
.filter((event) => event.type === "m.room.message" && event.content?.msgtype === "m.text")
|
||||
.map((event) => ({
|
||||
id: event.event_id,
|
||||
sender: event.sender,
|
||||
body: event.content?.body || "",
|
||||
timestamp: event.origin_server_ts,
|
||||
own: event.sender === session.matrixUserId,
|
||||
}))
|
||||
.reverse(),
|
||||
}
|
||||
}
|
||||
|
||||
const sendGeneralRoomMessage = async (
|
||||
userId: string,
|
||||
tenantId: number | null,
|
||||
text: string
|
||||
) => {
|
||||
const message = text.trim()
|
||||
|
||||
if (!message) {
|
||||
throw Object.assign(
|
||||
new Error("Message text is required"),
|
||||
{ statusCode: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const room = await provisionTenantRoom(userId, tenantId, {
|
||||
key: "allgemein",
|
||||
name: "Allgemeiner Chat",
|
||||
})
|
||||
|
||||
const session = await ensureCurrentUserJoinedRoom(userId, tenantId, {
|
||||
roomId: room.roomId,
|
||||
alias: room.alias,
|
||||
})
|
||||
const txnId = `${Date.now()}-${randomBytes(8).toString("hex")}`
|
||||
|
||||
const response = await requestMatrixJson<{ event_id: string }>(
|
||||
`/_matrix/client/v3/rooms/${encodeURIComponent(room.roomId)}/send/m.room.message/${encodeURIComponent(txnId)}`,
|
||||
session.accessToken,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
msgtype: "m.text",
|
||||
body: message,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
id: response.event_id,
|
||||
sender: session.matrixUserId,
|
||||
body: message,
|
||||
timestamp: Date.now(),
|
||||
own: true,
|
||||
roomId: room.roomId,
|
||||
alias: room.alias,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getStatus,
|
||||
matrixUserIdForUser,
|
||||
@@ -616,5 +763,8 @@ export function matrixService(server: FastifyInstance) {
|
||||
provisionCurrentTenantSpace,
|
||||
getTenantRoomStatus,
|
||||
provisionTenantRoom,
|
||||
createAccessTokenForUser,
|
||||
getGeneralRoomMessages,
|
||||
sendGeneralRoomMessage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,4 +74,27 @@ export default async function communicationRoutes(server: FastifyInstance) {
|
||||
.send({ error: err.message || "Matrix room provisioning failed" })
|
||||
}
|
||||
})
|
||||
|
||||
server.get("/communication/matrix/rooms/general/messages", async (req, reply) => {
|
||||
try {
|
||||
return await matrix.getGeneralRoomMessages(req.user.user_id, req.user.tenant_id)
|
||||
} catch (err: any) {
|
||||
req.log.error(err)
|
||||
return reply
|
||||
.code(err.statusCode || 500)
|
||||
.send({ error: err.message || "Matrix messages failed" })
|
||||
}
|
||||
})
|
||||
|
||||
server.post("/communication/matrix/rooms/general/messages", async (req, reply) => {
|
||||
try {
|
||||
const body = req.body as { text?: string }
|
||||
return await matrix.sendGeneralRoomMessage(req.user.user_id, req.user.tenant_id, body.text || "")
|
||||
} catch (err: any) {
|
||||
req.log.error(err)
|
||||
return reply
|
||||
.code(err.statusCode || 500)
|
||||
.send({ error: err.message || "Matrix message send failed" })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user