Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions cmd/server/servers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package main
import (
"fmt"
"net/http"

"robinplatform.dev/smgr/internal/manager"
)

func init() {
http.HandleFunc("/api/GetServers", GetServers)
http.HandleFunc("/api/StartServer", StartServer)
http.HandleFunc("/api/CheckServerHealth", CheckServerHealth)
}

func GetServers(res http.ResponseWriter, req *http.Request) {
Expand All @@ -16,3 +20,35 @@ func GetServers(res http.ResponseWriter, req *http.Request) {
sendJson(res, serverManager.Servers)
}
}

func StartServer(res http.ResponseWriter, req *http.Request) {
fmt.Printf("StartServer Running\n")
config := manager.DevServerConfig{
Name: "hello",
Command: "ls",
}

if err := manager.StartServer(config); err != nil {
sendError(res, 500, fmt.Errorf("failed to discover servers: %w", err))
} else {
sendJson(res, map[string]any{
"success": true,
})
}
}

func CheckServerHealth(res http.ResponseWriter, req *http.Request) {
fmt.Printf("CheckHealth Running\n")
config := manager.DevServerConfig{
Name: "hello",
Command: "/bin/ls",
}

if err := manager.CheckServerHealth(config); err != nil {
sendError(res, 500, fmt.Errorf("failed to discover servers: %w", err))
} else {
sendJson(res, map[string]any{
"success": true,
})
}
}
35 changes: 30 additions & 5 deletions internal/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (
)

type DevServerConfig struct {
Name string `json:"-"`
HealthChecks []health.HealthCheck `json:"healthChecks,omitempty"`
Command string `json:"command"`
Command string `json:"command"`
}

func (config *DevServerConfig) UnmarshalJSON(data []byte) error {
Expand All @@ -39,8 +40,8 @@ func (config *DevServerConfig) UnmarshalJSON(data []byte) error {
type ServerManagerConfig struct {
FilePath string `json:"-"`

Name string `json:"name"`
DevServers map[string]DevServerConfig `json:"devServers"`
Name string `json:"name"`
DevServers []DevServerConfig `json:"devServers"`
}

func (config *ServerManagerConfig) load() error {
Expand All @@ -54,10 +55,34 @@ func (config *ServerManagerConfig) load() error {
return fmt.Errorf("failed to read server config from %s: %w", config.FilePath, err)
}

if err := json.Unmarshal(buf, config); err != nil {
type ServerConfigJSON struct {
HealthChecks []health.HealthCheck `json:"healthChecks,omitempty"`
Command string `json:"command"`
}

type ConfigJSON struct {
Name string `json:"name"`
DevServers map[string]ServerConfigJSON `json:"devServers"`
}

var configTmp ConfigJSON
if err := json.Unmarshal(buf, &configTmp); err != nil {
return fmt.Errorf("failed to unmarshal server config from %s: %w", config.FilePath, err)
}

config.Name = configTmp.Name
config.DevServers = make([]DevServerConfig, 0, len(configTmp.DevServers))

for name, value := range configTmp.DevServers {
server := DevServerConfig{
Name: name,
HealthChecks: value.HealthChecks,
Command: value.Command,
}

config.DevServers = append(config.DevServers, server)
}

if config.Name == "" {
config.Name = filepath.Base(filepath.Dir(config.FilePath))
}
Expand Down Expand Up @@ -93,7 +118,7 @@ func (manager *ServerManager) DiscoverServers(projectPath string) error {
if dirEntry.IsDir() {
return nil
}

if filepath.Base(filename) == "robin.servers.json" {
fmt.Printf("Discovered server config: %s\n", filename)

Expand Down
103 changes: 103 additions & 0 deletions internal/manager/start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package manager

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)

func StartServer(config DevServerConfig) error {
type Input struct {
AppId string `json:"appId"`
ProcessKey string `json:"processKey"`
Command string `json:"command"`
Args []string `json:"args"`
}

input := Input{
AppId: "server-manager",
ProcessKey: config.Name,
Command: "/bin/bash",
Args: []string{"-c", config.Command},
}

jsonValue, err := json.Marshal(input)
if err != nil {
return err
}

resp, err := http.Post("http://localhost:9010/api/apps/rpc/StartProcess", "application/json", bytes.NewBuffer(jsonValue))
if err != nil {
return err
}

defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)

fmt.Printf("StartServer resp body: %s\n", string(body))

return nil
}

func StopServer(config DevServerConfig) error {
type Input struct {
AppId string `json:"appId"`
ProcessKey string `json:"processKey"`
}

input := Input{
AppId: "server-manager",
ProcessKey: config.Name,
}

jsonValue, err := json.Marshal(input)
if err != nil {
return err
}

resp, err := http.Post("http://localhost:9010/api/apps/rpc/StopProcess", "application/json", bytes.NewBuffer(jsonValue))
if err != nil {
return err
}

defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)

fmt.Printf("resp body: %s\n", string(body))

return nil
}

func CheckServerHealth(config DevServerConfig) error {
type Input struct {
AppId string `json:"appId"`
ProcessKey string `json:"processKey"`
}

input := Input{
AppId: "server-manager",
ProcessKey: config.Name,
}

jsonValue, err := json.Marshal(input)
if err != nil {
return err
}

resp, err := http.Post("http://localhost:9010/api/apps/rpc/CheckProcessHealth", "application/json", bytes.NewBuffer(jsonValue))
if err != nil {
return err
}

defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)

fmt.Printf("CheckServer resp body: %s\n", string(body))

return nil
}
19 changes: 19 additions & 0 deletions src/ControlPanel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import { useHistory } from "../hooks/useHistory";
import { useSelectedServer } from "../hooks/useSelectedServer";
import { runAppMethod } from "@robinplatform/toolkit";
import { useMutation } from "@tanstack/react-query";
import React from "react";
import { z } from "zod";

export const ControlPanel: React.FC = () => {
const { selectedServer } = useSelectedServer();
const history = useHistory();
const { mutate } = useMutation<null, unknown, void, [string]>({
mutationKey: ["StartServer", selectedServer],
mutationFn: async (): Promise<null> => {
await runAppMethod({
methodName: "StartServer",
resultType: z.any(),
data: {
server: selectedServer,
},
});

return null;
},
});

return (
<div className='serverControlPanel'>
<h1 className='serverControlPanelHeading'>{selectedServer}</h1>

<p>{history.pathname}</p>

<button onClick={() => mutate()}>Start</button>
</div>
);
};
11 changes: 10 additions & 1 deletion src/ServerList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ const ServerListItem: React.FC<{
onClick: () => void;
}> = ({ server, onClick }) => {
const { selectedServer } = useSelectedServer();
const { data: health } = useRpcQuery(
"CheckServerHealth",
{
name: server.name,
},
{
refetchInterval: 3000,
},
);

return (
<button
Expand All @@ -19,7 +28,7 @@ const ServerListItem: React.FC<{
})}
onClick={onClick}
>
{server.name}
{server.name} {JSON.stringify(health)}
</button>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const App = () => {

return (
<div className="appContainer robin-pad robin-bg-dark-blue robin-rounded">
<div className="serverListContainer">
<div className="leftSidebar">
<ServerList />
</div>

Expand Down
16 changes: 11 additions & 5 deletions src/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@ import { createReactRpcBridge } from "@robinplatform/toolkit/react/rpc";
import { z } from "zod";

export const ServerType = z.object({
name: z.string(),
name: z.string(),
});
export type ServerType = z.infer<typeof ServerType>;

const { useRpcQuery } = createReactRpcBridge({
GetServers: {
input: z.object({}),
output: z.array(ServerType),
},
GetServers: {
input: z.object({}),
output: z.array(ServerType),
},
CheckServerHealth: {
input: z.object({
name: z.string(),
}),
output: z.string(),
},
});

export { useRpcQuery };