Selaa lähdekoodia

First endpoint to add movies

Gildas Chabot 4 vuotta sitten
commit
c994c23215
7 muutettua tiedostoa jossa 266 lisäystä ja 0 poistoa
  1. 1 0
      .gitignore
  2. 41 0
      api/api.go
  3. 62 0
      cmd/movies/main.go
  4. 58 0
      collection.go
  5. 82 0
      movies.go
  6. 21 0
      movies_test.go
  7. 1 0
      omdb/trop-belle-pour-toi.json

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
1
+movies.json

+ 41 - 0
api/api.go

@@ -0,0 +1,41 @@
1
+package api
2
+
3
+import (
4
+	"encoding/json"
5
+	"io/ioutil"
6
+	"net/http"
7
+
8
+	"gogs.gildas.ch/gildas/movies"
9
+)
10
+
11
+type Error struct {
12
+	Error string `json: "error"`
13
+}
14
+
15
+func returnError(w http.ResponseWriter, status int, err error) {
16
+	w.Header().Set("Content-Type", "application/json")
17
+	w.WriteHeader(status)
18
+	json.NewEncoder(w).Encode(Error{Error: err.Error()})
19
+}
20
+
21
+func AddMovieHandler(c *movies.Collection) http.HandlerFunc {
22
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
23
+		if r.Method != "POST" {
24
+			return
25
+		}
26
+
27
+		b, err := ioutil.ReadAll(r.Body)
28
+		if err != nil {
29
+			returnError(w, http.StatusBadRequest, err)
30
+			return
31
+		}
32
+
33
+		m, err := movies.Unmarshal(b)
34
+		if err != nil {
35
+			returnError(w, http.StatusBadRequest, err)
36
+			return
37
+		}
38
+
39
+		c.Add(m)
40
+	})
41
+}

+ 62 - 0
cmd/movies/main.go

@@ -0,0 +1,62 @@
1
+package main
2
+
3
+import (
4
+	"fmt"
5
+	"log"
6
+	"net/http"
7
+	"os"
8
+	"time"
9
+
10
+	"gogs.gildas.ch/gildas/movies"
11
+	"gogs.gildas.ch/gildas/movies/api"
12
+)
13
+
14
+const (
15
+	dataFile = "movies.json"
16
+)
17
+
18
+func main() {
19
+	var collection *movies.Collection
20
+	if _, err := os.Stat(dataFile); !os.IsNotExist(err) {
21
+		c, err := movies.Import(dataFile)
22
+		if err != nil {
23
+			log.Fatal(err)
24
+		}
25
+		collection = c
26
+	} else {
27
+		collection = &movies.Collection{}
28
+	}
29
+
30
+	http.Handle("/add-movie", api.AddMovieHandler(collection))
31
+
32
+	port := "8080"
33
+	if p := os.Getenv("PORT"); p != "" {
34
+		port = p
35
+	}
36
+
37
+	stopExport := make(chan bool)
38
+	go export(collection, stopExport)
39
+	defer func() { stopExport <- true }()
40
+
41
+	fmt.Println("Listening...")
42
+	err := http.ListenAndServe(":"+port, nil)
43
+	fmt.Println("Server stopped with error:", err)
44
+}
45
+
46
+func export(c *movies.Collection, stop <-chan bool) {
47
+	for {
48
+		select {
49
+		case <-time.After(30 * time.Second):
50
+			if c.HasChanged() {
51
+				err := c.Export(dataFile)
52
+				if err != nil {
53
+					log.Fatal(err)
54
+					return
55
+				}
56
+				fmt.Printf("Exported fresh data to %q.\n", dataFile)
57
+			}
58
+		case <-stop:
59
+			return
60
+		}
61
+	}
62
+}

+ 58 - 0
collection.go

@@ -0,0 +1,58 @@
1
+package movies
2
+
3
+import (
4
+	"encoding/json"
5
+	"io/ioutil"
6
+	"sync"
7
+)
8
+
9
+type Collection struct {
10
+	Movies []*Movie
11
+
12
+	mutex      sync.RWMutex
13
+	hasChanged bool
14
+}
15
+
16
+func Import(filename string) (*Collection, error) {
17
+	b, err := ioutil.ReadFile(filename)
18
+	if err != nil {
19
+		return nil, err
20
+	}
21
+
22
+	var c Collection
23
+	if err := json.Unmarshal(b, &c); err != nil {
24
+		return nil, err
25
+	}
26
+
27
+	return &c, nil
28
+}
29
+
30
+func (c *Collection) Export(filename string) error {
31
+	c.mutex.RLock()
32
+	defer c.mutex.RUnlock()
33
+
34
+	b, err := json.Marshal(c)
35
+	if err != nil {
36
+		return err
37
+	}
38
+
39
+	err = ioutil.WriteFile(filename, b, 0644)
40
+	if err != nil {
41
+		return err
42
+	}
43
+
44
+	c.hasChanged = false
45
+	return nil
46
+}
47
+
48
+func (c *Collection) Add(m *Movie) {
49
+	c.mutex.Lock()
50
+	defer c.mutex.Unlock()
51
+
52
+	c.Movies = append(c.Movies, m)
53
+	c.hasChanged = true
54
+}
55
+
56
+func (c *Collection) HasChanged() bool {
57
+	return c.hasChanged
58
+}

+ 82 - 0
movies.go

@@ -0,0 +1,82 @@
1
+package movies
2
+
3
+import (
4
+	"encoding/json"
5
+	"fmt"
6
+	"strconv"
7
+	"strings"
8
+)
9
+
10
+type Movie struct {
11
+	Title    string
12
+	Director string
13
+	Poster   string
14
+	Rating   Rating
15
+
16
+	OMDB OMDBMovie
17
+}
18
+
19
+type Rating struct {
20
+	Note  float64
21
+	Votes int64
22
+}
23
+
24
+type OMDBMovie struct {
25
+	Title      string
26
+	Year       string
27
+	Rated      string
28
+	Released   string
29
+	Runtime    string
30
+	Genre      string
31
+	Director   string
32
+	Writer     string
33
+	Actors     string
34
+	Plot       string
35
+	Language   string
36
+	Country    string
37
+	Awards     string
38
+	Poster     string
39
+	Ratings    []OMDBRating
40
+	Metascore  string
41
+	IMDBRating string `json: "imdbRating"`
42
+	IMDBVotes  string `json: "imdbVotes"`
43
+	IMDBID     string `json: "imdbID"`
44
+	Type       string
45
+	DVD        string
46
+	BoxOffice  string
47
+	Production string
48
+	Website    string
49
+	Response   string
50
+}
51
+
52
+type OMDBRating struct {
53
+	Source, Value string
54
+}
55
+
56
+func Unmarshal(b []byte) (*Movie, error) {
57
+	var omdb OMDBMovie
58
+	if err := json.Unmarshal(b, &omdb); err != nil {
59
+		return nil, err
60
+	}
61
+
62
+	note, err := strconv.ParseFloat(omdb.IMDBRating, 64)
63
+	if err != nil {
64
+		return nil, fmt.Errorf("cannot convert %q to float64: %w", omdb.IMDBRating, err)
65
+	}
66
+
67
+	votes, err := strconv.ParseInt(strings.ReplaceAll(omdb.IMDBVotes, ",", ""), 10, 64)
68
+	if err != nil {
69
+		return nil, fmt.Errorf("cannot convert %q to int: %w", omdb.IMDBVotes, err)
70
+	}
71
+
72
+	return &Movie{
73
+		Title:    omdb.Title,
74
+		Director: omdb.Director,
75
+		Poster:   omdb.Poster,
76
+		Rating: Rating{
77
+			Note:  note,
78
+			Votes: votes,
79
+		},
80
+		OMDB: omdb,
81
+	}, nil
82
+}

+ 21 - 0
movies_test.go

@@ -0,0 +1,21 @@
1
+package movies
2
+
3
+import (
4
+	"fmt"
5
+	"io/ioutil"
6
+	"testing"
7
+)
8
+
9
+func TestUnmarshal(t *testing.T) {
10
+	b, err := ioutil.ReadFile("omdb/trop-belle-pour-toi.json")
11
+	if err != nil {
12
+		t.Fatal(err)
13
+	}
14
+
15
+	m, err := Unmarshal(b)
16
+	if err != nil {
17
+		t.Fatal(err)
18
+	}
19
+
20
+	fmt.Println(m)
21
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 0
omdb/trop-belle-pour-toi.json