main.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. package main
  2. import (
  3. "fmt"
  4. "http"
  5. "exp/template"
  6. mysql "github.com/Philio/GoMySQL"
  7. "os"
  8. "json"
  9. "strconv"
  10. "time"
  11. )
  12. type Song struct {
  13. Yid string
  14. Title string
  15. User string
  16. }
  17. type Playlist struct {
  18. Id string
  19. }
  20. var templates map[string]*template.Template
  21. const debug = true
  22. var db *mysql.Client
  23. func home(w http.ResponseWriter, r *http.Request) {
  24. fmt.Fprintf(w, "path is %s", r.URL.Path[1:])
  25. }
  26. func playlist(w http.ResponseWriter, r *http.Request) {
  27. id := r.URL.Path[len("/p/"):]
  28. if len(id) != 8 {
  29. http.Redirect(w, r, "/", 303)
  30. return
  31. }
  32. playlist := Playlist{Id: id}
  33. if debug {
  34. t, err := template.ParseFile("templates/p.html")
  35. if err != nil {
  36. http.Error(w, err.String(), http.StatusInternalServerError)
  37. return
  38. }
  39. err = t.Execute(w, playlist)
  40. if err != nil {
  41. w.Write([]byte(err.String()))
  42. fmt.Fprintln(os.Stderr, err.String())
  43. return
  44. }
  45. } else {
  46. err := templates["p"].Execute(w, playlist)
  47. if err != nil {
  48. fmt.Fprintln(os.Stderr, err.String())
  49. }
  50. }
  51. }
  52. func add(w http.ResponseWriter, r *http.Request) {
  53. q := r.URL.Query()
  54. pid := getpid(q.Get("pid"))
  55. if pid == -1 {
  56. http.Error(w, "invalid pid", http.StatusInternalServerError)
  57. return
  58. }
  59. sql := "INSERT INTO `song` (`pid`,`yid`,`title`,`user`) VALUES(%d,'%s','%s','%s')"
  60. sql = fmt.Sprintf(sql, pid,
  61. db.Escape(q.Get("yid")),
  62. db.Escape(q.Get("title")),
  63. db.Escape(q.Get("user")))
  64. err := db.Query(sql)
  65. if err != nil {
  66. http.Error(w, err.String(), http.StatusInternalServerError)
  67. return
  68. }
  69. w.Write([]byte("1"))
  70. addUpdate(pid, addAction,
  71. &Song{Yid: q.Get("yid"), Title: q.Get("title"), User: q.Get("user")})
  72. }
  73. func remove(w http.ResponseWriter, r *http.Request) {
  74. q := r.URL.Query()
  75. pid := getpid(q.Get("pid"))
  76. if pid == -1 {
  77. http.Error(w, "invalid pid", http.StatusInternalServerError)
  78. return
  79. }
  80. sql := "DELETE FROM `song` WHERE `pid` = %d AND yid = '%s'"
  81. sql = fmt.Sprintf(sql, pid, q.Get("yid"))
  82. err := db.Query(sql)
  83. if err != nil {
  84. http.Error(w, err.String(), http.StatusInternalServerError)
  85. return
  86. }
  87. w.Write([]byte("1"))
  88. addUpdate(pid, removeAction, &Song{Yid: q.Get("yid")})
  89. }
  90. func move(w http.ResponseWriter, r *http.Request) {
  91. q := r.URL.Query()
  92. pid := getpid(q.Get("pid"))
  93. if pid == -1 {
  94. http.Error(w, "invalid pid", http.StatusInternalServerError)
  95. return
  96. }
  97. direction, err := strconv.Atoui(q.Get("direction"))
  98. if err != nil {
  99. http.Error(w, err.String(), http.StatusInternalServerError)
  100. return
  101. }
  102. err = db.Start()
  103. if err != nil {
  104. http.Error(w, err.String(), http.StatusInternalServerError)
  105. return
  106. }
  107. order, err := queryInt("SELECT `order` FROM `song` WHERE `yid` = ? AND `pid` = ?",
  108. q.Get("yid"), pid)
  109. if err != nil {
  110. http.Error(w, err.String(), http.StatusInternalServerError)
  111. return
  112. }
  113. newOrder := order
  114. if direction == moveUpAction && order > 0 {
  115. newOrder--
  116. } else if direction == moveDownAction {
  117. newOrder++
  118. } else {
  119. http.Error(w, "invalid direction or cannot move up", http.StatusInternalServerError)
  120. return
  121. }
  122. sql := "UPDATE `song` SET `order` = %d WHERE `order` = %d AND pid = %d"
  123. sql = fmt.Sprintf(sql, order, newOrder, pid)
  124. err = db.Query(sql)
  125. if err != nil {
  126. http.Error(w, err.String(), http.StatusInternalServerError)
  127. return
  128. } else if db.AffectedRows != 1 {
  129. db.Rollback()
  130. http.Error(w, "invalid direction for this song", http.StatusInternalServerError)
  131. return
  132. }
  133. // there are now two songs with that order, so also check yid
  134. sql = "UPDATE `song` SET `order` = %d WHERE `order` = %d AND pid = %d AND yid = '%s'"
  135. sql = fmt.Sprintf(sql, newOrder, order, pid, q.Get("yid"))
  136. err = db.Query(sql)
  137. if err != nil {
  138. db.Rollback()
  139. http.Error(w, err.String(), http.StatusInternalServerError)
  140. return
  141. }
  142. err = db.Commit()
  143. if err != nil {
  144. http.Error(w, err.String(), http.StatusInternalServerError)
  145. return
  146. }
  147. w.Write([]byte("1"))
  148. addUpdate(pid, direction, &Song{Yid: q.Get("yid")})
  149. }
  150. func poll(w http.ResponseWriter, r *http.Request) {
  151. q := r.URL.Query()
  152. timestamp := q.Get("timestamp")
  153. if timestamp == "0" {
  154. query, err := db.Prepare("SELECT `yid`,`title`,`user` FROM `playlist` JOIN `song` WHERE `id` = ? ORDER BY `order` ASC")
  155. if err != nil {
  156. http.Error(w, err.String(), http.StatusInternalServerError)
  157. return
  158. }
  159. err = query.BindParams(q.Get("pid"))
  160. if err != nil {
  161. http.Error(w, err.String(), http.StatusInternalServerError)
  162. return
  163. }
  164. err = query.Execute()
  165. if err != nil {
  166. http.Error(w, err.String(), http.StatusInternalServerError)
  167. return
  168. }
  169. updates := make([]Update, 0, 2)
  170. for {
  171. song := new(Song)
  172. query.BindResult(&song.Yid, &song.Title, &song.User)
  173. eof, err := query.Fetch()
  174. if err != nil {
  175. http.Error(w, err.String(), http.StatusInternalServerError)
  176. return
  177. }
  178. if eof {
  179. break
  180. }
  181. updates = append(updates, Update{Song: song, Action: addAction, Timestamp: time.Nanoseconds()})
  182. }
  183. err = query.FreeResult()
  184. if err != nil {
  185. http.Error(w, err.String(), http.StatusInternalServerError)
  186. return
  187. }
  188. output, err := json.MarshalForHTML(updates)
  189. if err != nil {
  190. http.Error(w, err.String(), http.StatusInternalServerError)
  191. return
  192. }
  193. w.Write(output)
  194. } else {
  195. timestamp, err := strconv.Atoi64(q.Get("timestamp"))
  196. if err != nil {
  197. http.Error(w, err.String(), http.StatusInternalServerError)
  198. return
  199. }
  200. var update *Update
  201. for i := 0; i < 30; i++ {
  202. update = getUpdates(getpid(q.Get("pid")), timestamp)
  203. if update != nil {
  204. w.Write([]byte("["))
  205. for update != nil {
  206. output, err := json.MarshalForHTML(update)
  207. if err == nil {
  208. w.Write(output)
  209. }
  210. update = update.Next
  211. if update != nil {
  212. w.Write([]byte(","))
  213. }
  214. }
  215. w.Write([]byte("]"))
  216. return
  217. }
  218. time.Sleep(1e9) // 1 second
  219. }
  220. w.Write([]byte("[]"))
  221. }
  222. }
  223. func main() {
  224. templates = make(map[string]*template.Template)
  225. for _, path := range []string{"p"} {
  226. t, err := template.ParseFile("templates/" + path + ".html")
  227. if err != nil {
  228. fmt.Println(err)
  229. return
  230. }
  231. templates[path] = t
  232. }
  233. var err os.Error
  234. //db, err = mysql.DialTCP("raylu.net", "audio", "audio", "audio")
  235. db, err = mysql.DialTCP("173.228.31.111", "audio", "audio", "audio")
  236. if err != nil {
  237. fmt.Println(err)
  238. os.Exit(1)
  239. }
  240. db.Reconnect = true
  241. http.HandleFunc("/", home)
  242. http.HandleFunc("/p/", playlist)
  243. http.HandleFunc("/add/", add)
  244. http.HandleFunc("/remove/", remove)
  245. http.HandleFunc("/move/", move)
  246. http.HandleFunc("/poll/", poll)
  247. err = http.ListenAndServe("localhost:8000", nil)
  248. if err != nil {
  249. fmt.Println(err)
  250. os.Exit(1)
  251. }
  252. }