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.
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.

gomic.go 8.1KB

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. }