diff --git a/fableous-be/handlers/websocket.go b/fableous-be/handlers/websocket.go index bb13fa61..eb6ffec3 100644 --- a/fableous-be/handlers/websocket.go +++ b/fableous-be/handlers/websocket.go @@ -5,7 +5,6 @@ import ( "log" "os" "sync" - "time" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" @@ -224,13 +223,14 @@ func (m *module) ControllerCommandWorker(conn *websocket.Conn, sess *activeSessi _ = sess.hubConn.WriteJSON(message) case constants.WSMessageTypeAudio: go func() { - if filename := m.SavePayload(sess, message, true); filename != "" { + message.Data.ID = sess.currentPage // override page numbber + if filename, page := m.SavePayload(sess, message, true); filename != "" { _ = sess.hubConn.WriteJSON(datatransfers.WSMessage{ Type: constants.WSMessageTypeAudio, Role: role, Data: datatransfers.WSMessageData{ WSPaintMessageData: datatransfers.WSPaintMessageData{ - Text: fmt.Sprintf("%s/%s/%d/%s", sess.classroomID, sess.sessionID, sess.currentPage, filename), + Text: fmt.Sprintf("%s/%s/%d/%s", sess.classroomID, sess.sessionID, page, filename), }, }, }) @@ -254,23 +254,24 @@ func (m *module) ControllerCommandWorker(conn *websocket.Conn, sess *activeSessi return } -func (m *module) SavePayload(sess *activeSession, message datatransfers.WSMessage, isBase64 bool) (filename string) { +func (m *module) SavePayload(sess *activeSession, message datatransfers.WSMessage, isBase64 bool) (filename string, page int) { var err error var data []byte - if data, err = utils.ExtractPayload(message, isBase64); err != nil { + if data, page, err = utils.ExtractPayload(message, isBase64); err != nil { log.Println(err) return } - directory := fmt.Sprintf("%s/%d", utils.GetSessionStaticDir(sess.sessionID, sess.classroomID), sess.currentPage) + directory := fmt.Sprintf("%s/%d", utils.GetSessionStaticDir(sess.sessionID, sess.classroomID), page) if _, err = os.Stat(directory); os.IsNotExist(err) { if err = os.MkdirAll(directory, 0700); err != nil { log.Println(err) return } } + log.Println(message.Type, page) switch message.Type { case constants.WSMessageTypeAudio: - filename = fmt.Sprintf("%d.ogg", time.Now().Unix()) + filename = "audio.ogg" case constants.WSMessageTypeImage: filename = "image.png" case constants.WSMessageTypeManifest: @@ -279,7 +280,7 @@ func (m *module) SavePayload(sess *activeSession, message datatransfers.WSMessag return } var file *os.File - if file, err = os.OpenFile(fmt.Sprintf("%s/%s", directory, filename), os.O_WRONLY|os.O_CREATE, 0700); err != nil { + if file, err = os.OpenFile(fmt.Sprintf("%s/%s", directory, filename), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700); err != nil { log.Println(err) return } diff --git a/fableous-be/utils/websocket.go b/fableous-be/utils/websocket.go index 113cda7a..16388248 100644 --- a/fableous-be/utils/websocket.go +++ b/fableous-be/utils/websocket.go @@ -7,8 +7,9 @@ import ( "github.com/deco-finter/fableous/fableous-be/datatransfers" ) -func ExtractPayload(message datatransfers.WSMessage, isBase64 bool) (payload []byte, err error) { +func ExtractPayload(message datatransfers.WSMessage, isBase64 bool) (payload []byte, page int, err error) { stringPayload := message.Data.WSPaintMessageData.Text + page = message.Data.WSPaintMessageData.ID if isBase64 { b64String := strings.Split(stringPayload, ",")[1] if payload, err = base64.StdEncoding.DecodeString(b64String); err != nil { diff --git a/fableous-fe/src/api.ts b/fableous-fe/src/api.ts index f9b49201..87b19863 100644 --- a/fableous-fe/src/api.ts +++ b/fableous-fe/src/api.ts @@ -136,6 +136,7 @@ export const restAPI = { method: "delete", }), }, + // @TODO: create POST for story saving } as ApiEndpoints; export const wsAPI = { diff --git a/fableous-fe/src/constant.ts b/fableous-fe/src/constant.ts index 95bdff43..e7ca316a 100644 --- a/fableous-fe/src/constant.ts +++ b/fableous-fe/src/constant.ts @@ -11,6 +11,8 @@ export enum WSMessageType { Join = "JOIN", Control = "CONTROL", Ping = "PING", + Image = "IMAGE", + Manifest = "MANIFEST", } export enum ToolMode { diff --git a/fableous-fe/src/containers/HubCanvasPage.tsx b/fableous-fe/src/containers/HubCanvasPage.tsx index 258c5507..80c57429 100644 --- a/fableous-fe/src/containers/HubCanvasPage.tsx +++ b/fableous-fe/src/containers/HubCanvasPage.tsx @@ -19,7 +19,13 @@ import { useRef, useEffect, useState, useCallback } from "react"; import { useParams } from "react-router-dom"; import * as yup from "yup"; import { restAPI, wsAPI } from "../api"; -import { Story, WSControlMessageData, WSJoinMessageData } from "../data"; +import { + Manifest, + Story, + WSControlMessageData, + WSJoinMessageData, + WSMessage, +} from "../data"; import AchievementButton from "../components/achievement/AchievementButton"; import Canvas from "../components/canvas/Canvas"; import CursorScreen, { Cursor } from "../components/canvas/CursorScreen"; @@ -216,29 +222,6 @@ export default function HubCanvasPage() { }); }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const exportCanvas = () => { - const canvas = document.createElement("canvas"); - const ctx = canvas.getContext("2d"); - const { width, height } = storyCanvasRef.current.getCanvas(); - if (!ctx) return; - canvas.width = width; - canvas.height = height; - ctx.beginPath(); - ctx.fillStyle = "white"; - ctx.fillRect(0, 0, width, height); - ctx.drawImage(backgroundCanvasRef.current.getCanvas(), 0, 0, width, height); - ctx.drawImage(characterCanvasRef.current.getCanvas(), 0, 0, width, height); - ctx.drawImage(storyCanvasRef.current.getCanvas(), 0, 0, width, height); - const link = document.createElement("a"); - link.download = "output.png"; - link.href = canvas - .toDataURL("image/png") - .replace("image/png", "image/octet-stream"); - link.click(); - console.log(JSON.stringify(storyTextShapes)); - }; - const isAllControllersJoined = (): boolean => { return ( [ @@ -251,6 +234,59 @@ export default function HubCanvasPage() { }; const onNextPage = () => { + console.log("posting this canvas page"); + if (hubState === HubState.DrawingSession) { + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + const { width, height } = storyCanvasRef.current.getCanvas(); + if (!ctx) return; + canvas.width = width; + canvas.height = height; + ctx.beginPath(); + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, width, height); + ctx.drawImage( + backgroundCanvasRef.current.getCanvas(), + 0, + 0, + width, + height + ); + ctx.drawImage( + characterCanvasRef.current.getCanvas(), + 0, + 0, + width, + height + ); + ctx.drawImage(storyCanvasRef.current.getCanvas(), 0, 0, width, height); + const link = document.createElement("a"); + link.download = "output.png"; + const dataUrl = canvas.toDataURL(); + wsConn?.send( + JSON.stringify({ + type: WSMessageType.Image, + data: { + id: currentPageIdx, + text: dataUrl, + }, + } as WSMessage) + ); + wsConn?.send( + JSON.stringify({ + type: WSMessageType.Manifest, + data: { + id: currentPageIdx, + text: JSON.stringify({ + texts: storyTextShapes, + audios: audioPaths, + achievements, + } as Manifest), + }, + } as WSMessage) + ); + } + setHubState(HubState.DrawingSession); wsConn?.send( JSON.stringify({ type: WSMessageType.Control, data: { nextPage: true } }) ); @@ -259,7 +295,6 @@ export default function HubCanvasPage() { return prev + 1; }); }; - const onBeginDrawing = () => { onNextPage(); setHubState(HubState.DrawingSession); diff --git a/fableous-fe/src/containers/StoryDetailPage.tsx b/fableous-fe/src/containers/StoryDetailPage.tsx index 7b251adc..2618e14c 100644 --- a/fableous-fe/src/containers/StoryDetailPage.tsx +++ b/fableous-fe/src/containers/StoryDetailPage.tsx @@ -50,7 +50,7 @@ export default function StoryDetailPage() { useEffect(() => { if (manifest) setTextShapes(manifest.texts); - if (manifest) setAudioPaths(manifest.audios.map((audio) => audio.text)); + if (manifest) setAudioPaths(manifest.audios); // eslint-disable-next-line react-hooks/exhaustive-deps }, [manifest]); diff --git a/fableous-fe/src/data.ts b/fableous-fe/src/data.ts index 1460bb61..afbf7c50 100644 --- a/fableous-fe/src/data.ts +++ b/fableous-fe/src/data.ts @@ -82,7 +82,7 @@ export interface ControllerJoin { } export interface Manifest { texts: TextShapeMap; - audios: { text: string }[]; + audios: string[]; achievements: Achievement; }