diff --git a/internal/httpserver/httpserver.go b/internal/httpserver/httpserver.go index b31dc53..fc79481 100644 --- a/internal/httpserver/httpserver.go +++ b/internal/httpserver/httpserver.go @@ -65,13 +65,17 @@ func New(hub *ws.Hub, cfg config.Config, srvOpts ...ServerOptions) *http.Server // registerStatic wires the asset routes: // -// - /sdk.js -> 301 /sdk/index.js (import.meta.url resolves correctly for relative imports) -// - /sdk/ -> ES-module SDK files served from cfg.SDKDir -// - / -> /sdk/index.js redirect (bare URL returns the SDK entry) -// - / -> matching file under cfg.PublicDir -// - anything -> public/status.xml fallback +// - /sdk.js -> 301 /sdk/index.js (import.meta.url resolves correctly) +// - /sdk/ -> ES-module SDK files served from cfg.SDKDir +// - /studio -> Studio product HTML (built-in UI) +// - /studio/ -> Studio JS/CSS assets under public/studio/ +// - / -> /sdk/index.js redirect (bare URL returns the SDK entry) +// - / -> matching file under cfg.PublicDir +// - anything -> public/status.xml fallback func registerStatic(mux *http.ServeMux, cfg config.Config) { - statusDoc := filepath.Join(cfg.PublicDir, "status.xml") + statusDoc := filepath.Join(cfg.PublicDir, "status.xml") + studioDir := filepath.Join(cfg.PublicDir, "studio") + studioHTML := filepath.Join(studioDir, "index.html") // /sdk.js → /sdk/index.js: keeps import.meta.url = /sdk/index.js so that // ./EventTarget.js etc. resolve to /sdk/EventTarget.js (same origin). @@ -80,6 +84,13 @@ func registerStatic(mux *http.ServeMux, cfg config.Config) { }) mux.Handle("/sdk/", http.StripPrefix("/sdk/", http.FileServer(http.Dir(cfg.SDKDir)))) + // /studio → Studio product (built-in management UI). + // /studio/ → JS/CSS assets (ColumnView.js, Studio.js, style.css, …). + mux.HandleFunc("/studio", func(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, studioHTML) + }) + mux.Handle("/studio/", http.StripPrefix("/studio/", http.FileServer(http.Dir(studioDir)))) + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { http.Redirect(w, r, "/sdk/index.js", http.StatusFound) diff --git a/sdk/studio/Column.js b/public/studio/Column.js similarity index 100% rename from sdk/studio/Column.js rename to public/studio/Column.js diff --git a/sdk/studio/ColumnView.js b/public/studio/ColumnView.js similarity index 98% rename from sdk/studio/ColumnView.js rename to public/studio/ColumnView.js index 56a1585..6ebb4f8 100644 --- a/sdk/studio/ColumnView.js +++ b/public/studio/ColumnView.js @@ -1,7 +1,7 @@ // Miller-column view: manages a horizontal row of up to 5 columns. // Selecting an item in column N removes columns N+1…end and adds the // new column opened by that item's onSelect callback. -import Column from './Column.js'; +import Column from '/studio/Column.js'; export default class ColumnView { constructor(container) { diff --git a/sdk/studio/index.js b/public/studio/Studio.js similarity index 98% rename from sdk/studio/index.js rename to public/studio/Studio.js index 29fa33b..58548c3 100644 --- a/sdk/studio/index.js +++ b/public/studio/Studio.js @@ -3,14 +3,14 @@ // Hierarchy: Network → Groups → Peers → Devices → Streams → Quality // // Usage: -// import Studio from '/sdk/studio/index.js'; +// import Studio from '/studio/Studio.js'; // const studio = new Studio(mwse, '#app'); // studio.mount(); // // The Studio is purely additive: it renders into the given container and // never modifies the MWSE SDK state except through the public SDK API. -import ColumnView from './ColumnView.js'; -import { MediaSources } from '../webrtc/index.js'; +import ColumnView from '/studio/ColumnView.js'; +import { MediaSources } from '/sdk/webrtc/index.js'; export default class Studio { constructor(mwse, container) { diff --git a/public/studio/app.js b/public/studio/app.js new file mode 100644 index 0000000..c71510f --- /dev/null +++ b/public/studio/app.js @@ -0,0 +1,23 @@ +import MWSE from '/sdk/index.js'; +import Studio from '/studio/Studio.js'; + +const mwse = new MWSE(); +const studio = new Studio(mwse, document.getElementById('app')); + +const loadingEl = document.getElementById('loading'); +const loadingMsg = document.getElementById('loading-msg'); + +mwse.on('scope', () => { + loadingEl.classList.add('hidden'); + studio.mount(); +}); + +mwse.on('close', () => { + loadingMsg.textContent = 'Bağlantı kesildi — yeniden bağlanılıyor…'; + loadingEl.classList.remove('hidden'); +}); + +mwse.on('error', err => { + loadingMsg.textContent = `Hata: ${err.message}`; + loadingEl.classList.remove('hidden'); +}); diff --git a/public/studio/index.html b/public/studio/index.html new file mode 100644 index 0000000..8bce985 --- /dev/null +++ b/public/studio/index.html @@ -0,0 +1,46 @@ + + + + + + MWSE Studio + + + +
+ +
+
Sunucuya bağlanıyor…
+
+
+ + + + diff --git a/sdk/studio/style.css b/public/studio/style.css similarity index 100% rename from sdk/studio/style.css rename to public/studio/style.css