Skip to content

Commit

Permalink
Add filewatcher for config files (#63)
Browse files Browse the repository at this point in the history
This adds the filewatcher and forwards events to the frontend. It also
sets up the widgets as something that can be controlled with a config
file.
  • Loading branch information
oneirocosm authored Jun 20, 2024
1 parent c7f76d5 commit 21fa9a6
Show file tree
Hide file tree
Showing 13 changed files with 369 additions and 31 deletions.
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ bin
frontend/dist
frontend/node_modules
*.min.*
frontend/app/store/services.ts
frontend/types/gotypes.d.ts
13 changes: 13 additions & 0 deletions cmd/server/main-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/wavetermdev/thenextwave/pkg/filestore"
"github.com/wavetermdev/thenextwave/pkg/service"
"github.com/wavetermdev/thenextwave/pkg/wavebase"
"github.com/wavetermdev/thenextwave/pkg/wconfig"
"github.com/wavetermdev/thenextwave/pkg/web"
"github.com/wavetermdev/thenextwave/pkg/wstore"
)
Expand All @@ -34,6 +35,10 @@ func doShutdown(reason string) {
defer cancelFn()
// TODO deal with flush in progress
filestore.WFS.FlushCache(ctx)
watcher := wconfig.GetWatcher()
if watcher != nil {
watcher.Close()
}
time.Sleep(200 * time.Millisecond)
os.Exit(0)
})
Expand Down Expand Up @@ -62,6 +67,13 @@ func stdinReadWatch() {
}
}

func configWatcher() {
watcher := wconfig.GetWatcher()
if watcher != nil {
watcher.Start()
}
}

func main() {
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
log.SetPrefix("[wavesrv] ")
Expand Down Expand Up @@ -106,6 +118,7 @@ func main() {
}
installShutdownSignalHandlers()
go stdinReadWatch()
configWatcher()

go web.RunWebSocketServer()
go func() {
Expand Down
9 changes: 9 additions & 0 deletions frontend/app/store/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const workspaceAtom: jotai.Atom<Workspace> = jotai.atom((get) => {
}
return WOS.getObjectValue(WOS.makeORef("workspace", windowData.workspaceid), get);
});
const settingsConfigAtom = jotai.atom(null) as jotai.PrimitiveAtom<SettingsConfigType>;
const tabAtom: jotai.Atom<Tab> = jotai.atom((get) => {
const windowData = get(windowDataAtom);
if (windowData == null) {
Expand All @@ -72,6 +73,7 @@ const atoms = {
client: clientAtom,
waveWindow: windowDataAtom,
workspace: workspaceAtom,
settingsConfigAtom: settingsConfigAtom,
tabAtom: tabAtom,
};

Expand Down Expand Up @@ -173,6 +175,13 @@ function handleWSEventMessage(msg: WSEventType) {
console.log("unsupported event", msg);
return;
}
if (msg.eventtype == "config") {
const data: WatcherUpdate = msg.data;
globalStore.set(settingsConfigAtom, data.update);

console.log("config", data);
return;
}
if (msg.eventtype == "blockfile") {
const fileData: WSFileEventData = msg.data;
const fileSubject = getFileSubject(fileData.zoneid, fileData.filename);
Expand Down
9 changes: 9 additions & 0 deletions frontend/app/store/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,21 @@ export const ClientService = new ClientServiceType()

// fileservice.FileService (file)
class FileServiceType {
AddWidget(arg1: WidgetsConfigType): Promise<void> {
return WOS.callBackendService("file", "AddWidget", Array.from(arguments))
}
GetSettingsConfig(): Promise<any> {
return WOS.callBackendService("file", "GetSettingsConfig", Array.from(arguments))
}
GetWaveFile(arg1: string, arg2: string): Promise<any> {
return WOS.callBackendService("file", "GetWaveFile", Array.from(arguments))
}
ReadFile(arg1: string): Promise<FullFile> {
return WOS.callBackendService("file", "ReadFile", Array.from(arguments))
}
RemoveWidget(arg1: number): Promise<void> {
return WOS.callBackendService("file", "RemoveWidget", Array.from(arguments))
}
StatFile(arg1: string): Promise<FileInfo> {
return WOS.callBackendService("file", "StatFile", Array.from(arguments))
}
Expand Down
50 changes: 20 additions & 30 deletions frontend/app/workspace/workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
import { TabBar } from "@/app/tab/tabbar";
import { TabContent } from "@/app/tab/tabcontent";
import { atoms, createBlock } from "@/store/global";
import * as services from "@/store/services";
import * as jotai from "jotai";
import * as React from "react";
import { CenteredDiv } from "../element/quickelems";

import "./workspace.less";

function Widgets() {
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
const newWidgetModalVisible = React.useState(false);
async function clickTerminal() {
const termBlockDef = {
controller: "shell",
Expand All @@ -18,51 +22,37 @@ function Widgets() {
createBlock(termBlockDef);
}

async function clickPreview(fileName: string) {
const markdownDef = {
view: "preview",
meta: { file: fileName },
};
createBlock(markdownDef);
}

async function clickPlot() {
const plotDef: BlockDef = {
view: "plot",
};
createBlock(plotDef);
}

async function clickEdit() {
const editDef: BlockDef = {
view: "codeedit",
};
createBlock(editDef);
}
async function handleWidgetSelect(blockDef: BlockDef) {
createBlock(blockDef);
}

async function handleCreateWidget(newWidget: WidgetsConfigType) {
await services.FileService.AddWidget(newWidget);
}

async function handleRemoveWidget(idx: number) {
await services.FileService.RmWidget(idx);
}

return (
<div className="workspace-widgets">
<div className="widget" onClick={() => clickTerminal()}>
<i className="fa fa-solid fa-square-terminal fa-fw" />
</div>
<div className="widget" onClick={() => clickPreview("~/work/wails/thenextwave/README.md")}>
<i className="fa fa-solid fa-files fa-fw" />
</div>
<div className="widget" onClick={() => clickPreview("~/work/wails/thenextwave/go.mod")}>
<i className="fa fa-solid fa-files fa-fw" />
</div>
<div className="widget" onClick={() => clickPreview("~/work/wails/thenextwave/build/appicon.png")}>
<i className="fa fa-solid fa-files fa-fw" />
</div>
<div className="widget" onClick={() => clickPreview("~")}>
<i className="fa fa-solid fa-files fa-fw" />
</div>
<div className="widget" onClick={() => clickPlot()}>
<i className="fa fa-solid fa-chart-simple fa-fw" />
</div>
<div className="widget" onClick={() => clickEdit()}>
<i className="fa-sharp fa-solid fa-pen-to-square"></i>
</div>
{settingsConfig.widgets.map((data, idx) => (
<div className="widget" onClick={() => handleWidgetSelect(data.blockdef)} key={`widget-${idx}`}>
<i className={data.icon}></i>
</div>
))}
<div className="widget no-hover">
<i className="fa fa-solid fa-plus fa-fw" />
</div>
Expand Down
6 changes: 6 additions & 0 deletions frontend/types/gotypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,12 @@ declare global {
updates?: WaveObjUpdate[];
};

// wconfig.WidgetsConfigType
type WidgetsConfigType = {
icon: string;
blockdef: BlockDef;
};

// wstore.WinSize
type WinSize = {
width: number;
Expand Down
3 changes: 2 additions & 1 deletion frontend/wave.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

import { globalStore, globalWS, initWS } from "@/store/global";
import { atoms, globalStore, globalWS, initWS } from "@/store/global";
import * as services from "@/store/services";
import * as WOS from "@/store/wos";
import * as React from "react";
Expand Down Expand Up @@ -37,6 +37,7 @@ document.addEventListener("DOMContentLoaded", async () => {
const client = await WOS.loadAndPinWaveObject<Client>(WOS.makeORef("client", clientId));
const waveWindow = await WOS.loadAndPinWaveObject<WaveWindow>(WOS.makeORef("window", windowId));
await WOS.loadAndPinWaveObject<Workspace>(WOS.makeORef("workspace", waveWindow.workspaceid));
globalStore.set(atoms.settingsConfigAtom, await services.FileService.GetSettingsConfig());
services.ObjectService.SetActiveTab(waveWindow.activetabid); // no need to wait
const reactElem = React.createElement(App, null, null);
const elem = document.getElementById("main");
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ toolchain go1.22.1
require (
github.com/alexflint/go-filemutex v1.3.0
github.com/creack/pty v1.1.18
github.com/fsnotify/fsnotify v1.7.0
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/google/uuid v1.4.0
github.com/gorilla/handlers v1.5.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
Expand Down
16 changes: 16 additions & 0 deletions pkg/service/fileservice/fileservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/wavetermdev/thenextwave/pkg/filestore"
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
"github.com/wavetermdev/thenextwave/pkg/wavebase"
"github.com/wavetermdev/thenextwave/pkg/wconfig"
)

const MaxFileSize = 10 * 1024 * 1024 // 10M
Expand Down Expand Up @@ -117,3 +118,18 @@ func (fs *FileService) GetWaveFile(id string, path string) (any, error) {
}
return file, nil
}

func (fs *FileService) GetSettingsConfig() interface{} {
watcher := wconfig.GetWatcher()
return watcher.GetSettingsConfig()
}

func (fs *FileService) AddWidget(newWidget wconfig.WidgetsConfigType) error {
watcher := wconfig.GetWatcher()
return watcher.AddWidget(newWidget)
}

func (fs *FileService) RemoveWidget(idx uint) error {
watcher := wconfig.GetWatcher()
return watcher.RmWidget(idx)
}
4 changes: 4 additions & 0 deletions pkg/util/utilfn/mimetypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -1180,8 +1180,12 @@ var StaticMimeTypeMap = map[string]string{
".gl": "video/gl",
".m4s": "video/iso.segment",
".mj2": "video/mj2",
".m4v": "video/mp4",
".mkv": "video/mp4",
".mov": "video/mp4",
".mp4": "video/mp4",
".mpeg": "video/mpeg",
".mpg": "video/mpeg",
".ogv": "video/ogg",
".qt": "video/quicktime",
".uvh": "video/vnd.dece.hd",
Expand Down
Loading

0 comments on commit 21fa9a6

Please sign in to comment.