5         "golang.org/x/net/websocket" 
  17 const formatString 
= "2006-01-02T15:04" 
  19 var config ServerConfig 
= NewServerConfig() 
  22         configFlag 
:= flag
.String("c", "", "path to configuration file") 
  24         //generateFlag := flag.String("g", "", "create a template config file with specified name then exit") 
  27         if *configFlag 
== "" { 
  28                 log
.Fatal("must specify a configuration file with -c") 
  30         config
.LoadFromFile(*configFlag
) 
  32         log
.Println("Hello, World! Woo broadcast time") 
  34         defer db
.CloseDatabase() 
  37         InitAudioFiles(config
.AudioFilesPath
) 
  40         http
.HandleFunc("/", homePage
) 
  41         http
.HandleFunc("/login", logInPage
) 
  42         http
.HandleFunc("/logout", logOutPage
) 
  43         http
.HandleFunc("/secret", secretPage
) 
  45         http
.HandleFunc("/playlist/", playlistSection
) 
  46         http
.HandleFunc("/file/", fileSection
) 
  47         http
.HandleFunc("/radio/", radioSection
) 
  49         http
.Handle("/radiosync", websocket
.Handler(RadioSync
)) 
  50         http
.Handle("/websync", websocket
.Handler(WebSync
)) 
  51         http
.Handle("/audio-files/", http
.StripPrefix("/audio-files/", http
.FileServer(http
.Dir(config
.AudioFilesPath
)))) 
  53         err 
:= http
.ListenAndServe(config
.BindAddress
+":"+strconv
.Itoa(config
.Port
), nil) 
  59 type HomeData 
struct { 
  64 func homePage(w http
.ResponseWriter
, r 
*http
.Request
) { 
  65         tmpl 
:= template
.Must(template
.ParseFiles("templates/index.html")) 
  73 func secretPage(w http
.ResponseWriter
, r 
*http
.Request
) { 
  74         user
, err 
:= currentUser(w
, r
) 
  76                 http
.Redirect(w
, r
, "/login", http
.StatusFound
) 
  79         tmpl 
:= template
.Must(template
.ParseFiles("templates/index.html")) 
  82                 Username
: user
.username 
+ ", you are special", 
  87 type LogInData 
struct { 
  91 func logInPage(w http
.ResponseWriter
, r 
*http
.Request
) { 
  92         log
.Println("Log in page!") 
  94         username 
:= r
.Form
["username"] 
  95         password 
:= r
.Form
["password"] 
  98                 log
.Println("Looks like we have a username", username
[0]) 
  99                 if username
[0] == "admin" && password
[0] == "test" { 
 100                         createSessionCookie(w
) 
 101                         http
.Redirect(w
, r
, "/", http
.StatusFound
) 
 104                         err 
= "Incorrect login" 
 112         tmpl 
:= template
.Must(template
.ParseFiles("templates/login.html")) 
 113         tmpl
.Execute(w
, data
) 
 116 func playlistSection(w http
.ResponseWriter
, r 
*http
.Request
) { 
 117         path 
:= strings
.Split(r
.URL
.Path
, "/") 
 122         if path
[2] == "new" { 
 123                 editPlaylistPage(w
, r
, 0) 
 124         } else if path
[2] == "submit" && r
.Method 
== "POST" { 
 126         } else if path
[2] == "delete" && r
.Method 
== "POST" { 
 128         } else if path
[2] == "" { 
 131                 id
, err 
:= strconv
.Atoi(path
[2]) 
 136                 editPlaylistPage(w
, r
, id
) 
 140 func fileSection(w http
.ResponseWriter
, r 
*http
.Request
) { 
 141         path 
:= strings
.Split(r
.URL
.Path
, "/") 
 146         if path
[2] == "upload" { 
 148         } else if path
[2] == "delete" && r
.Method 
== "POST" { 
 150         } else if path
[2] == "" { 
 158 func radioSection(w http
.ResponseWriter
, r 
*http
.Request
) { 
 159         path 
:= strings
.Split(r
.URL
.Path
, "/") 
 164         if path
[2] == "new" { 
 165                 editRadioPage(w
, r
, 0) 
 166         } else if path
[2] == "submit" && r
.Method 
== "POST" { 
 168         } else if path
[2] == "delete" && r
.Method 
== "POST" { 
 170         } else if path
[2] == "" { 
 173                 id
, err 
:= strconv
.Atoi(path
[2]) 
 178                 editRadioPage(w
, r
, id
) 
 182 type PlaylistsPageData 
struct { 
 186 func playlistsPage(w http
.ResponseWriter
, _ 
*http
.Request
) { 
 187         data 
:= PlaylistsPageData
{ 
 188                 Playlists
: db
.GetPlaylists(), 
 190         tmpl 
:= template
.Must(template
.ParseFiles("templates/playlists.html")) 
 191         err 
:= tmpl
.Execute(w
, data
) 
 197 type RadiosPageData 
struct { 
 201 func radiosPage(w http
.ResponseWriter
, _ 
*http
.Request
) { 
 202         data 
:= RadiosPageData
{ 
 203                 Radios
: db
.GetRadios(), 
 205         tmpl 
:= template
.Must(template
.ParseFiles("templates/radios.html")) 
 206         err 
:= tmpl
.Execute(w
, data
) 
 212 type EditPlaylistPageData 
struct { 
 214         Entries  
[]PlaylistEntry
 
 218 func editPlaylistPage(w http
.ResponseWriter
, r 
*http
.Request
, id 
int) { 
 219         var data EditPlaylistPageData
 
 220         for _
, f 
:= range files
.Files() { 
 221                 data
.Files 
= append(data
.Files
, f
.Name
) 
 224                 data
.Playlist
.Enabled 
= true 
 225                 data
.Playlist
.Name 
= "New Playlist" 
 226                 data
.Playlist
.StartTime 
= time
.Now().Format(formatString
) 
 227                 data
.Entries 
= append(data
.Entries
, PlaylistEntry
{}) 
 229                 playlist
, err 
:= db
.GetPlaylist(id
) 
 234                 data
.Playlist 
= playlist
 
 235                 data
.Entries 
= db
.GetEntriesForPlaylist(id
) 
 237         tmpl 
:= template
.Must(template
.ParseFiles("templates/playlist.html")) 
 238         tmpl
.Execute(w
, data
) 
 241 func submitPlaylist(w http
.ResponseWriter
, r 
*http
.Request
) { 
 245                 id
, err 
:= strconv
.Atoi(r
.Form
.Get("playlistId")) 
 249                 _
, err 
= time
.Parse(formatString
, r
.Form
.Get("playlistStartTime")) 
 254                 p
.Enabled 
= r
.Form
.Get("playlistEnabled") == "1" 
 255                 p
.Name 
= r
.Form
.Get("playlistName") 
 256                 p
.StartTime 
= r
.Form
.Get("playlistStartTime") 
 258                 delays 
:= r
.Form
["delaySeconds"] 
 259                 filenames 
:= r
.Form
["filename"] 
 260                 isRelatives 
:= r
.Form
["isRelative"] 
 262                 entries 
:= make([]PlaylistEntry
, 0) 
 263                 for i 
:= range delays 
{ 
 265                         delay
, err 
:= strconv
.Atoi(delays
[i
]) 
 269                         e
.DelaySeconds 
= delay
 
 271                         e
.IsRelative 
= isRelatives
[i
] == "1" 
 272                         e
.Filename 
= filenames
[i
] 
 273                         entries 
= append(entries
, e
) 
 275                 cleanedEntries 
:= make([]PlaylistEntry
, 0) 
 276                 for _
, e 
:= range entries 
{ 
 277                         if e
.DelaySeconds 
!= 0 || e
.Filename 
!= "" { 
 278                                 cleanedEntries 
= append(cleanedEntries
, e
) 
 285                         id 
= db
.CreatePlaylist(p
) 
 287                 db
.SetEntriesForPlaylist(cleanedEntries
, id
) 
 288                 // Notify connected radios 
 289                 playlists
.NotifyChanges() 
 291         http
.Redirect(w
, r
, "/playlist/", http
.StatusFound
) 
 294 func deletePlaylist(w http
.ResponseWriter
, r 
*http
.Request
) { 
 297                 id
, err 
:= strconv
.Atoi(r
.Form
.Get("playlistId")) 
 301                 db
.DeletePlaylist(id
) 
 302                 playlists
.NotifyChanges() 
 304         http
.Redirect(w
, r
, "/playlist/", http
.StatusFound
) 
 307 type EditRadioPageData 
struct { 
 311 func editRadioPage(w http
.ResponseWriter
, r 
*http
.Request
, id 
int) { 
 312         var data EditRadioPageData
 
 314                 data
.Radio
.Name 
= "New Radio" 
 315                 data
.Radio
.Token 
= generateSession() 
 317                 radio
, err 
:= db
.GetRadio(id
) 
 324         tmpl 
:= template
.Must(template
.ParseFiles("templates/radio.html")) 
 325         tmpl
.Execute(w
, data
) 
 328 func submitRadio(w http
.ResponseWriter
, r 
*http
.Request
) { 
 332                 id
, err 
:= strconv
.Atoi(r
.Form
.Get("radioId")) 
 337                 radio
.Name 
= r
.Form
.Get("radioName") 
 338                 radio
.Token 
= r
.Form
.Get("radioToken") 
 340                         db
.UpdateRadio(radio
) 
 342                         db
.CreateRadio(radio
) 
 345         http
.Redirect(w
, r
, "/radio/", http
.StatusFound
) 
 348 func deleteRadio(w http
.ResponseWriter
, r 
*http
.Request
) { 
 351                 id
, err 
:= strconv
.Atoi(r
.Form
.Get("radioId")) 
 357         http
.Redirect(w
, r
, "/radio/", http
.StatusFound
) 
 360 type FilesPageData 
struct { 
 364 func filesPage(w http
.ResponseWriter
, _ 
*http
.Request
) { 
 365         data 
:= FilesPageData
{ 
 366                 Files
: files
.Files(), 
 368         log
.Println("file page data", data
) 
 369         tmpl 
:= template
.Must(template
.ParseFiles("templates/files.html")) 
 370         err 
:= tmpl
.Execute(w
, data
) 
 376 func deleteFile(w http
.ResponseWriter
, r 
*http
.Request
) { 
 379                 filename 
:= r
.Form
.Get("filename") 
 383                 files
.Delete(filename
) 
 385         http
.Redirect(w
, r
, "/file/", http
.StatusFound
) 
 388 func uploadFile(w http
.ResponseWriter
, r 
*http
.Request
) { 
 389         err 
:= r
.ParseMultipartForm(100 << 20) 
 390         file
, handler
, err 
:= r
.FormFile("file") 
 392                 path 
:= filepath
.Join(files
.Path(), filepath
.Base(handler
.Filename
)) 
 393                 f
, _ 
:= os
.Create(path
) 
 396                 log
.Println("uploaded file to", path
) 
 399         http
.Redirect(w
, r
, "/file/", http
.StatusFound
) 
 402 func logOutPage(w http
.ResponseWriter
, r 
*http
.Request
) { 
 403         clearSessionCookie(w
) 
 404         tmpl 
:= template
.Must(template
.ParseFiles("templates/logout.html"))