You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package main
  2. import "errors"
  3. import "log"
  4. import "os"
  5. import "path"
  6. import "net/http"
  7. import "io/ioutil"
  8. import "encoding/json"
  9. import "github.com/go-vgo/robotgo"
  10. import "github.com/BurntSushi/toml"
  11. type Config struct {
  12. BasePath string `toml:"base_path"`
  13. }
  14. type MousePosData struct {
  15. X int `json:"x"`
  16. Y int `json:"y"`
  17. }
  18. type ScreenSizeData struct {
  19. Width int `json:"width"`
  20. Height int `json:"height"`
  21. }
  22. type DirEntryData struct {
  23. Name string `json:"name"`
  24. Type string `json:"type"`
  25. }
  26. type ListDirData struct {
  27. Entries []DirEntryData `json:"entries"`
  28. }
  29. type Error struct {
  30. Error string `json:"error"`
  31. }
  32. func readConfig() (*Config, error) {
  33. confFile, err := os.Open("config.toml")
  34. if err != nil {
  35. return nil, err
  36. }
  37. defer confFile.Close()
  38. var conf Config
  39. _, err = toml.NewDecoder(confFile).Decode(&conf)
  40. if err != nil {
  41. return nil, err
  42. }
  43. return &conf, nil
  44. }
  45. type RW http.ResponseWriter
  46. type Req http.Request
  47. func handler(h func(w RW, req *Req) error) (
  48. func(w http.ResponseWriter, req *http.Request)) {
  49. return func(w http.ResponseWriter, req *http.Request) {
  50. err := h(RW(w), (*Req)(req))
  51. if err != nil {
  52. w.WriteHeader(400)
  53. err = json.NewEncoder(w).Encode(&Error{err.Error()})
  54. if err != nil {
  55. w.Write([]byte("Oh no, failed to encode error struct"))
  56. }
  57. }
  58. }
  59. }
  60. func main() {
  61. conf, err := readConfig()
  62. if err != nil {
  63. log.Fatal(err)
  64. }
  65. log.Printf("Config: %#v", conf)
  66. fs := http.FileServer(http.Dir("./web"))
  67. http.Handle("/", fs)
  68. http.HandleFunc("/api/screen-size", handler(func(w RW, req *Req) error {
  69. if req.Method == "GET" {
  70. var size ScreenSizeData
  71. size.Width, size.Height = robotgo.GetScreenSize()
  72. return json.NewEncoder(w).Encode(&size)
  73. } else {
  74. return errors.New("Invalid method: " + req.Method)
  75. }
  76. }))
  77. http.HandleFunc("/api/mouse-pos", handler(func(w RW, req *Req) error {
  78. if req.Method == "GET" {
  79. var pos MousePosData
  80. pos.X, pos.Y = robotgo.GetMousePos()
  81. return json.NewEncoder(w).Encode(&pos)
  82. } else if req.Method == "PUT" {
  83. var pos MousePosData
  84. err := json.NewDecoder(req.Body).Decode(&pos)
  85. if err != nil {
  86. return err
  87. }
  88. robotgo.MoveMouse(pos.X, pos.Y)
  89. return nil
  90. } else {
  91. return errors.New("Invalid method: " + req.Method)
  92. }
  93. }))
  94. http.HandleFunc("/api/dir/", handler(func(w RW, req *Req) error {
  95. if req.Method == "GET" {
  96. subPath := req.URL.Path[len("/api/dir/"):]
  97. dirEnts, err := ioutil.ReadDir(path.Join(conf.BasePath, subPath))
  98. if err != nil {
  99. return err
  100. }
  101. list := ListDirData{
  102. Entries: make([]DirEntryData, 0, len(dirEnts)),
  103. }
  104. for _, ent := range dirEnts {
  105. entType := "f"
  106. if ent.IsDir() {
  107. entType = "d"
  108. }
  109. list.Entries = append(list.Entries, DirEntryData{
  110. Name: ent.Name(),
  111. Type: entType,
  112. })
  113. }
  114. return json.NewEncoder(w).Encode(&list)
  115. } else {
  116. return errors.New("Invalid method: " + req.Method)
  117. }
  118. }))
  119. log.Println("Listening on :3000...")
  120. err = http.ListenAndServe("localhost:3000", nil)
  121. if err != nil {
  122. log.Fatal(err)
  123. }
  124. }