begin work on "test client"

This commit is contained in:
Merith-TK 2024-03-16 17:15:27 -07:00
parent 66268e6702
commit 0a563d8b02
9 changed files with 113 additions and 279 deletions

100
cmd/client/main.go Normal file
View file

@ -0,0 +1,100 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"net/url"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
func main() {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
host := "127.0.0.1:5000"
langURL := fmt.Sprintf("ws://%s/lang", host)
cmdURL := fmt.Sprintf("ws://%s/cmd", host)
debugURL := fmt.Sprintf("ws://%s/debug", host)
execURL := fmt.Sprintf("ws://%s/", host)
execConn, err := connectWebSocket(execURL)
if err != nil {
log.Fatal("Failed to connect to lang websocket:", err)
}
defer execConn.Close()
langConn, err := connectWebSocket(langURL)
if err != nil {
log.Fatal("Failed to connect to lang websocket:", err)
}
defer langConn.Close()
cmdConn, err := connectWebSocket(cmdURL)
if err != nil {
log.Fatal("Failed to connect to cmd websocket:", err)
}
defer cmdConn.Close()
debugConn, err := connectWebSocket(debugURL)
if err != nil {
log.Fatal("Failed to connect to debug websocket:", err)
}
defer debugConn.Close()
done := make(chan struct{})
go readMessages(langConn, "lang", done)
go readMessages(cmdConn, "cmd", done)
go readMessages(debugConn, "debug", done)
// Read the contents of source.txt
sourceFile := "source.txt"
sourceData, err := ioutil.ReadFile(sourceFile)
if err != nil {
log.Fatal("Failed to read source file:", err)
}
// create execConn off of / endpoint
// Send the contents over the lang websocket
err = execConn.WriteMessage(websocket.TextMessage, sourceData)
if err != nil {
log.Fatal("Failed to send source data over lang websocket:", err)
}
select {
case <-interrupt:
fmt.Println("Interrupt signal received, closing connections...")
close(done)
time.Sleep(1 * time.Second)
return
}
}
func connectWebSocket(urlStr string) (*websocket.Conn, error) {
u, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
return nil, err
}
return conn, nil
}
func readMessages(conn *websocket.Conn, name string, done chan struct{}) {
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Error reading message from", name, "websocket:", err)
return
}
fmt.Printf("Received message from %s: %s\n", name, message)
}
}

104
cmd/server/main.go Normal file
View file

@ -0,0 +1,104 @@
package main
/*
fn fetch_python_location() -> String {
let output = Command::new("which python")
.output()
.expect("Failed to execute command");
let output = String::from_utf8_lossy(&output.stdout);
output.trim().to_string()
output
}
*/
import (
"fmt"
"log"
"net/http"
"os"
"strings"
"github.com/gorilla/websocket"
)
const (
WS_HOST = "0.0.0.0"
WS_PORT = 5000
)
var Upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
func main() {
http.HandleFunc("/", HandleWs)
// output handlers
http.HandleFunc("/lang", HandleLang)
// if ./workspace/ directory does not exist, create it
if _, err := os.Stat("./workspace/"); os.IsNotExist(err) {
os.Mkdir("./workspace/", 0755)
}
addr := fmt.Sprintf("%s:%d", WS_HOST, WS_PORT)
log.Println("Server started at", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
func HandleWs(w http.ResponseWriter, r *http.Request) {
log.Println("[/] Connection from", r.RemoteAddr)
c, err := Upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
// get the first line of the message from the client
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
// print the message to the console
log.Printf("recv: %s", message)
// seperate message into chunks by newline
msg := strings.Split(string(message), "\n")
handleCase(msg[0], strings.Join(msg[1:], "\n"))
c.WriteMessage(websocket.TextMessage, []byte("Forwarding to output handler: "+msg[0]+"\n"))
}
}
func HandleLang(w http.ResponseWriter, r *http.Request) {
log.Println("[/lang] Connection from", r.RemoteAddr)
// upgrade the connection to a websocket
c, err := Upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
// defer c.Close()
c.WriteMessage(websocket.TextMessage, []byte("Connected to output handler"))
go func() {
for {
// wait for message from client
_, message, err := c.ReadMessage()
if err != nil {
log.Println("Error reading from client", err)
break
}
// convert message to string
msg := string(message)
log.Println("Received message from client:", msg)
// convert pyReader to string
newstr := make([]byte, 1024)
n, err := pyReader.Read(newstr)
if err != nil {
log.Println("Error reading from pyReader")
break
}
c.WriteMessage(websocket.TextMessage, newstr[:n])
}
}()
}

8
cmd/server/output.go Normal file
View file

@ -0,0 +1,8 @@
package main
import (
"io"
)
// pythonOut is a channel that will be written to by the python runtime via exec.Command
var pyReader, pyWriter = io.Pipe()

69
cmd/server/runtime.go Normal file
View file

@ -0,0 +1,69 @@
package main
import (
"log"
"os/exec"
"path/filepath"
"strings"
// import file writer
"os"
// import websocket
)
func handleCase(caseName, data string) string {
// caseName = strings.ReplaceAll(caseName, "\n", "")
caseName = strings.ReplaceAll(caseName, ":", "")
log.Println("Handling case", caseName)
switch caseName {
case "python", "python3", "py":
runPython(data)
}
return ""
}
func runPython(data string) {
log.Println("Running python")
// create a file in the workspace directory
f, err := os.Create("./workspace/main.py")
if err != nil {
log.Println("Error creating file")
return
}
defer f.Close()
// write the data to the file
_, err = f.WriteString(data)
if err != nil {
log.Println("Error writing to file")
return
}
// find python, python3, or py in the system
fname, err := exec.LookPath("python3")
if err != nil {
log.Println("Python not found")
} else {
log.Println("Python found at", fname)
}
// fname := "C:\\Users\\zachd\\scoop\\shims\\python3.exe"
// if main.py does not exist, return
if _, err := os.Stat("./workspace/main.py"); os.IsNotExist(err) {
log.Println("File does not exist")
return
}
cmd := exec.Command(fname, "./main.py")
cmd.Dir = filepath.ToSlash("./workspace/")
// set the command's stdout to the pipe writer
cmd.Stdout = pyWriter
// set the command's stderr to the pipe writer
cmd.Stderr = pyWriter
// start the command
cmd.Run()
log.Println("Python runtime finished")
}