This is just an exercise to learn some go. This program downloads a list of images and creates a webserver with a photo gallery to serve them. The images in the repo are technical comics.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package main
  2. import (
  3. "bufio"
  4. "html/template"
  5. "io"
  6. "io/ioutil"
  7. "log"
  8. "math/rand"
  9. "net/http"
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. )
  14. // downloadComics descarga una lista de imágenes y las escribe en un directorio.
  15. // El directorio seguirá el formato `origin/$originName/`. El parámetro `origin`
  16. // es un string que contiene el nombre o "namespace" del comic.
  17. func downloadComics(origin string) {
  18. var filePath string
  19. var directories = "./comics/" + strings.ToLower(origin) + "/"
  20. // Leer un fichero y mostrar el error de haberlo
  21. fileHandle, err := os.Open("./origin/" + origin + ".txt")
  22. if err != nil {
  23. log.Fatal(err)
  24. }
  25. // Cerrar el fichero aplazado
  26. defer fileHandle.Close()
  27. // Crear un objeto escaner, que se usará para leer el fichero origen y
  28. // hacer un bucle, siendo cada iteración una linea de este fichero.
  29. fileScanner := bufio.NewScanner(fileHandle)
  30. for fileScanner.Scan() {
  31. // Inizializar y asignar el valor de linea a la variable url
  32. url := fileScanner.Text()
  33. // Este if es exclusivo para los libros de colorear, tienen todos el
  34. // mismo nombre y hay que darles un nombre distinto
  35. if filepath.Base(url) == "Web.pdf" {
  36. splitedUrl := strings.Split(url, "/")
  37. filePath = directories + splitedUrl[4] + "-" +
  38. splitedUrl[len(splitedUrl)-1]
  39. } else {
  40. filePath = directories + filepath.Base(url)
  41. }
  42. // Si el fichero ya existe, seguir con el siguiente fichero
  43. if _, err := os.Stat(filePath); !os.IsNotExist(err) {
  44. continue
  45. }
  46. // Descargar fichero
  47. response, err := http.Get(url)
  48. if err != nil {
  49. // Mostrar el error de haberlo
  50. log.Print("error downloading " + url)
  51. log.Print(err)
  52. } else {
  53. // Imprimir por pantalla el resultado correcto de la descarga del
  54. // fichero
  55. log.Print("successfully downloaded " + url)
  56. }
  57. // Cerrar la petición de descarga cuando termine
  58. defer response.Body.Close()
  59. // Crear los directorios
  60. os.MkdirAll(directories, os.ModePerm)
  61. // Crear el fichero vacío y mostrar el error de haberlo
  62. file, err := os.Create(filePath)
  63. if err != nil {
  64. log.Print("error creating " + filePath)
  65. log.Print(err)
  66. }
  67. // Cerrar el fichero de forma aplazada
  68. defer file.Close()
  69. // Escribir el contenido descargado en el fichero y mostrar el error de
  70. // haberlo
  71. _, err = io.Copy(file, response.Body)
  72. if err != nil {
  73. log.Print("error writing" + filePath)
  74. log.Print(err)
  75. }
  76. }
  77. }
  78. // ls devuelve un array de strings con los comics del origen que recibe.
  79. func ls(origin string) []string {
  80. // Declarar variable
  81. var images []string
  82. // Declarar e instanciar variable con el valor `statc/$origen.html`.
  83. var path = "comics" + strings.Replace(filepath.Clean(origin), ".html", "",
  84. -1)
  85. // Listar ficheros de del directorio `./static/$origin.html` y capturar el
  86. // error de haberlo
  87. _images, err := ioutil.ReadDir(path)
  88. if err != nil {
  89. log.Print("the path " + path + " doesn't exist")
  90. }
  91. // Convertir el array de os.FileInfo a un array de strings
  92. for _, entry := range _images {
  93. images = append(images, "/"+path+"/"+entry.Name())
  94. }
  95. return images
  96. }
  97. // getOrigins devuelve un array de strings con los origenes detectados.
  98. // Los orígenes se detectan haciendo un ls del directorio de `origins`, en el
  99. // que hay directorios con la extensión `.txt`.
  100. func getOrigins() []string {
  101. // Declarar variable
  102. var origins []string
  103. // Listar ficheros del directorio `./origin/` y captura el error de haberlo
  104. files, err := ioutil.ReadDir("./origin/")
  105. if err != nil {
  106. log.Fatal(err)
  107. }
  108. // Iterar sobre los ficheros del directorio anterior, creando un array de
  109. // strings con el nombre de la ruta completo de los ficheros
  110. for _, f := range files {
  111. if f.Name() != "random.txt" {
  112. origins = append(origins, (strings.Replace(f.Name(), ".txt", "",
  113. -1)))
  114. }
  115. }
  116. return origins
  117. }
  118. // comicServer sirve el html de los endpoint de los origenes. Según la petición
  119. // que llegue, se renderizan los comics de ese origen. El parámetro `w` es el
  120. // objeto que renderizará el html. El parámetro `r` es la petición de entrada,
  121. // de la que se saca el nombre del origen.
  122. func comicServer(w http.ResponseWriter, r *http.Request) {
  123. // Declarar array de strings
  124. var images []string
  125. var existingOrigins []string
  126. // Declarar un diccionario de array de strings
  127. var parameter = make(map[string][]string)
  128. // Declarar e instanciar con el valor `./templates/$origen`.
  129. variableTemplate := filepath.Join("./templates",
  130. filepath.Clean(r.URL.Path)+".html")
  131. // Declarar e instanciar con el valor `./templates/layout.html`.
  132. layoutTemplate := filepath.Join("./templates", "layout.html")
  133. // Coger los origenes
  134. existingOrigins = getOrigins()
  135. // Listar los ficheros del origen
  136. images = ls(filepath.Clean(r.URL.Path))
  137. // Asignar al diccionario las imagenes y los origenes
  138. parameter["images"] = images
  139. parameter["origins"] = existingOrigins
  140. // Pasar la función ToLower a los templates
  141. funcMap := template.FuncMap{
  142. "ToLower": strings.ToLower,
  143. }
  144. // Declarar, instanciar y ejecutar el objeto template
  145. tmpl, _ := template.New("random").Funcs(funcMap).ParseFiles(layoutTemplate,
  146. variableTemplate)
  147. // Renderizar el html
  148. tmpl.ExecuteTemplate(w, "layout", parameter)
  149. }
  150. // random sirve el html del endpoint /random/. Muestra un comic aleatorio de los
  151. // origenes definidos en el fichero random.txt. El parámetro `w` es el objeto
  152. // que renderizará el html. El parámetro `r` es la petición de entrada, de la
  153. // que se saca el nombre del origen.
  154. func random(w http.ResponseWriter, r *http.Request) {
  155. // Declarar variables
  156. var usableOrigin []string
  157. var usedOrigin string
  158. var existingOrigins []string
  159. var parameter = make(map[string][]string)
  160. // Definir los templates
  161. layoutTemplate := "./templates/layout.html"
  162. randomTemplate := "./templates/random.html"
  163. // Leer un fichero en formato bytes y mostrar el error de haberlo
  164. fileHandle, err := os.Open("./origin/random.txt")
  165. if err != nil {
  166. log.Fatal(err)
  167. }
  168. // Cerrar el fichero
  169. defer fileHandle.Close()
  170. // Crear un objeto escaner, que se usará para leer el fichero origen y
  171. // hacer un bucle, siendo cada iteración una linea de este fichero.
  172. fileScanner := bufio.NewScanner(fileHandle)
  173. for fileScanner.Scan() {
  174. // Inizializar y asignar el valor de linea a la variable usableOrigin
  175. usableOrigin = append(usableOrigin, fileScanner.Text())
  176. }
  177. // Definir aleatoriamente que origen se servirá
  178. usedOrigin = usableOrigin[rand.Intn(len(usableOrigin))]
  179. // Coger los origenes
  180. existingOrigins = getOrigins()
  181. // Listar los ficheros del origen
  182. images := ls("/" + usedOrigin)
  183. // Sortear que imagen mostrar
  184. randomImage := rand.Intn(len(images))
  185. // Asignar al diccionario la imagen y los origenes
  186. parameter["images"] = append(parameter["images"], images[randomImage])
  187. parameter["origins"] = existingOrigins
  188. // Pasar la función ToLower a los templates
  189. funcMap := template.FuncMap{
  190. "ToLower": strings.ToLower,
  191. }
  192. // Declarar, instanciar y ejecutar el objeto template
  193. tmpl, _ := template.New("random").Funcs(funcMap).ParseFiles(layoutTemplate,
  194. randomTemplate)
  195. // Renderizar el html
  196. tmpl.ExecuteTemplate(w, "layout", parameter)
  197. }
  198. func main() {
  199. // Declarar variable
  200. var origins []string
  201. var port = ":8080"
  202. // Añadir el directorio `static` como directorio disponible en el servidor
  203. // web
  204. fs := http.FileServer(http.Dir("./static/"))
  205. // Añadir el directorio `comics` como directorio disponible en el servidor
  206. // web
  207. cm := http.FileServer(http.Dir("./comics/"))
  208. // Asociar el endpoint `/static/` con el directorio `static`
  209. http.Handle("/static/", http.StripPrefix("/static/", fs))
  210. // Asociar el endpoint `/comics/` con el directorio `comics`
  211. http.Handle("/comics/", http.StripPrefix("/comics/", cm))
  212. // Instanciar variable con los origenes
  213. origins = getOrigins()
  214. for _, origin := range origins {
  215. // Descargar los comics de cada origen
  216. downloadComics(origin)
  217. // Asignar un endpoint a cada origen
  218. http.HandleFunc("/"+strings.ToLower(origin)+"/", comicServer)
  219. }
  220. // Hacer que random sea el endpoint por defecto
  221. http.HandleFunc("/", random)
  222. // Imprimir por pantalla la dirección del servidor web
  223. log.Println("Starting webserver at http://localhost" + port)
  224. // Crear y servir el servidor
  225. http.ListenAndServe(port, nil)
  226. }