Browse Source

initial commit

main
Martin Dørum 10 months ago
commit
4e24437ca6
10 changed files with 329 additions and 0 deletions
  1. 1
    0
      .gitignore
  2. 1
    0
      config.toml
  3. 8
    0
      go.mod
  4. 67
    0
      go.sum
  5. 148
    0
      main.go
  6. BIN
      web/favicon.png
  7. 44
    0
      web/files.html
  8. 18
    0
      web/index.html
  9. 0
    0
      web/style.css
  10. 42
    0
      web/util.js

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
/media

+ 1
- 0
config.toml View File

@@ -0,0 +1 @@
base_path = "./media"

+ 8
- 0
go.mod View File

@@ -0,0 +1,8 @@
module coffee.mort.mediator

go 1.16

require (
github.com/BurntSushi/toml v0.4.1
github.com/go-vgo/robotgo v0.99.0
)

+ 67
- 0
go.sum View File

@@ -0,0 +1,67 @@
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY=
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-vgo/robotgo v0.99.0 h1:Lp6kvic1/LxkSShf6KNjcrcE21FCFlonrCguQN96Ay4=
github.com/go-vgo/robotgo v0.99.0/go.mod h1:0+i2QWRmZtbIF02RwmiGfFj33Judprukd8ls5J6Eajg=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/gosseract v2.2.1+incompatible h1:Ry5ltVdpdp4LAa2bMjsSJH34XHVOV7XMi41HtzL8X2I=
github.com/otiai10/gosseract v2.2.1+incompatible/go.mod h1:XrzWItCzCpFRZ35n3YtVTgq5bLAhFIkascoRo8G32QE=
github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robotn/gohook v0.30.6 h1:hH2KzyRsThtOqQ4M2ZPiOaib4vx70pz1DqgrBm26vPk=
github.com/robotn/gohook v0.30.6/go.mod h1:FXryR68cDIho8rjE7MKxt4n4aK2FBqp+d/0HK4oiGP8=
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY=
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk=
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU=
github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc=
github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
github.com/vcaesar/gops v0.20.0 h1:SqP/rzDJh7Dy4/Obrjqv+ZftUig+b46BECj9cQ1mCTw=
github.com/vcaesar/gops v0.20.0/go.mod h1:EvpOHW7re4rBSzI1B/Rly0CxfT7C9lLo7Rpgs6IVpF0=
github.com/vcaesar/imgo v0.12.1 h1:/mmZPL0CQwXtdr73ouoCu8Z9gmfmdgaFYoG0YSZ1gdU=
github.com/vcaesar/imgo v0.12.1/go.mod h1:MwS4X0FXkLxshu8jMrHCLEM0S6JOQ6lU3drq5nO9AdE=
github.com/vcaesar/tt v0.11.0 h1:obQecjgbnAxxC6OYGY6yDvhGRW2PR5wD8Ma2uJH3WGA=
github.com/vcaesar/tt v0.11.0/go.mod h1:GHPxQYhn+7OgKakRusH7KJ0M5MhywoeLb8Fcffs/Gtg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9 h1:D0iM1dTCbD5Dg1CbuvLC/v/agLc79efSj/L35Q3Vqhs=
golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8=
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 148
- 0
main.go View File

@@ -0,0 +1,148 @@
package main

import "errors"
import "log"
import "os"
import "path"
import "net/http"
import "io/ioutil"
import "encoding/json"
import "github.com/go-vgo/robotgo"
import "github.com/BurntSushi/toml"

type Config struct {
BasePath string `toml:"base_path"`
}

type MousePosData struct {
X int `json:"x"`
Y int `json:"y"`
}

type ScreenSizeData struct {
Width int `json:"width"`
Height int `json:"height"`
}

type DirEntryData struct {
Name string `json:"name"`
Type string `json:"type"`
}

type ListDirData struct {
Entries []DirEntryData `json:"entries"`
}

type Error struct {
Error string `json:"error"`
}

func readConfig() (*Config, error) {
confFile, err := os.Open("config.toml")
if err != nil {
return nil, err
}
defer confFile.Close()

var conf Config
_, err = toml.NewDecoder(confFile).Decode(&conf)
if err != nil {
return nil, err
}

return &conf, nil
}

type RW http.ResponseWriter
type Req http.Request

func handler(h func(w RW, req *Req) error) (
func(w http.ResponseWriter, req *http.Request)) {
return func(w http.ResponseWriter, req *http.Request) {
err := h(RW(w), (*Req)(req))
if err != nil {
w.WriteHeader(400)
err = json.NewEncoder(w).Encode(&Error{err.Error()})
if err != nil {
w.Write([]byte("Oh no, failed to encode error struct"))
}
}
}
}

func main() {
conf, err := readConfig()
if err != nil {
log.Fatal(err)
}

log.Printf("Config: %#v", conf)

fs := http.FileServer(http.Dir("./web"))
http.Handle("/", fs)

http.HandleFunc("/api/screen-size", handler(func(w RW, req *Req) error {
if req.Method == "GET" {
var size ScreenSizeData
size.Width, size.Height = robotgo.GetScreenSize()
return json.NewEncoder(w).Encode(&size)
} else {
return errors.New("Invalid method: " + req.Method)
}
}))

http.HandleFunc("/api/mouse-pos", handler(func(w RW, req *Req) error {
if req.Method == "GET" {
var pos MousePosData
pos.X, pos.Y = robotgo.GetMousePos()
return json.NewEncoder(w).Encode(&pos)
} else if req.Method == "PUT" {
var pos MousePosData
err := json.NewDecoder(req.Body).Decode(&pos)
if err != nil {
return err
}

robotgo.MoveMouse(pos.X, pos.Y)
return nil
} else {
return errors.New("Invalid method: " + req.Method)
}
}))

http.HandleFunc("/api/dir/", handler(func(w RW, req *Req) error {
if req.Method == "GET" {
subPath := req.URL.Path[len("/api/dir/"):]
dirEnts, err := ioutil.ReadDir(path.Join(conf.BasePath, subPath))
if err != nil {
return err
}

list := ListDirData{
Entries: make([]DirEntryData, 0, len(dirEnts)),
}

for _, ent := range dirEnts {
entType := "f"
if ent.IsDir() {
entType = "d"
}

list.Entries = append(list.Entries, DirEntryData{
Name: ent.Name(),
Type: entType,
})
}

return json.NewEncoder(w).Encode(&list)
} else {
return errors.New("Invalid method: " + req.Method)
}
}))

log.Println("Listening on :3000...")
err = http.ListenAndServe("localhost:3000", nil)
if err != nil {
log.Fatal(err)
}
}

BIN
web/favicon.png View File


+ 44
- 0
web/files.html View File

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Mediator</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" type="image/png" href="favicon.png">
</head>

<body>
<div id="breadcrumbs"></div>

<ul id="files"></ul>

<script src="util.js"></script>
<script>
let filesEl = document.getElementById("files");
let breadcrumbsEl = document.getElementById("breadcrumbs");
let path = [];

function renderEntry(ent) {
if (ent.type == "d") {
return html("span", {}, [
html("text", ent.name + "/")]);
} else {
return html("span", {}, [
html("text", ent.name)]);
}
}

async function render() {
let resp = await api("GET", "dir/" + path.join("/"));
clearElement(filesEl);
for (let ent of resp.entries) {
filesEl.appendChild(renderEntry(ent));
}
}

render();
</script>
</body>

</html>

+ 18
- 0
web/index.html View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Mediator</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" type="image/png" href="favicon.png">
</head>

<body>
<div class="menu">
<a href="files.html">Files</a>
<a href="remote.html">Remote</a>
</div>
</body>

</html>

+ 0
- 0
web/style.css View File


+ 42
- 0
web/util.js View File

@@ -0,0 +1,42 @@
async function api(method, path, body = null) {
let options = {method};
if (body != null) {
options.body = JSON.stringify(body);
}

let resp = await fetch("/api/" + path, options).then(r => r.text());
let json = JSON.parse(resp);

if (json.error != null) {
throw new Error(json.error);
}

return json;
}

function html(name, attrs, children) {
if (name == "text") {
return document.createTextNode(attrs);
}

let el = document.createElement(name);
for (let key in attrs) {
if (!attrs.hasOwnProperty(key)) {
continue;
}

el.setAttribute(key, attrs[key]);
}

for (let child of children) {
el.appendChild(child);
}

return el;
}

function clearElement(el) {
while (el.firstChild) {
el.removeChild(el.firstChild);
}
}

Loading…
Cancel
Save