Skip to content

Commit

Permalink
Major rearchitecture
Browse files Browse the repository at this point in the history
- Shift everything around in main.go
- Use shortened json result as response to
front-end for development
- Follow advice from github on how to embed custom
css when using elm-reactor
elm-lang/elm-reactor#138 (comment)
  • Loading branch information
stuartnelson3 committed Oct 28, 2016
1 parent 9496c48 commit 7576afc
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 116 deletions.
249 changes: 141 additions & 108 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"path/filepath"
"regexp"
"strings"
"time"

"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
Expand All @@ -32,122 +33,23 @@ func main() {
)
flag.Parse()

if *host == "" || *user == "" || *password == "" {
if *host == "" || *user == "" || *password == "" || *dir == "" {
flag.Usage()
}

pair, err := dialSSHSFTP(*host, &ssh.ClientConfig{
User: *user,
Auth: []ssh.AuthMethod{
ssh.Password(*password),
},
})
// apiMatches := getRemoteFiles(*host, *user, *password, *dir)
f, err := os.Open("example.json")
if err != nil {
log.Fatal(err)
}

// remoteFiles := make(map[string]remoteFile)
remoteFiles := []remoteFile{}

walker := pair.sftpc.Walk(*dir)
i := 0
for walker.Step() {
if err := walker.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
if i == 10 {
break
}
remoteFilePath := walker.Path()
if remoteFilePath == *dir {
continue
}
// Make worker pool that searches the movie api for the titles

fi := walker.Stat()
if fi.IsDir() {
// We will read the contents and put them in the
// struct, but we aren't going to return individual
// files through the API.
walker.SkipDir()

fileInfos, err := pair.sftpc.ReadDir(remoteFilePath)
if err != nil {
log.Printf("error reading dir %s, skipping\n", remoteFilePath)
continue
}

// Should I check for .mkv in here and ditch the whole dir if it doesn't have a video in it?
// Probably since that's what I'm doing for the bare files..
rmf := make([]remoteFile, len(fileInfos), len(fileInfos))
var videoDir bool
for j, fileInfo := range fileInfos {
if filepath.Ext(remoteFilePath) == mkv {
videoDir = true
}
rmf[j] = remoteFile{
Title: filepath.Base(fileInfo.Name()),
FullPath: filepath.Join(remoteFilePath, fileInfo.Name()),
FileInfo: fileInfo,
}
}
if videoDir {
remoteFiles = append(remoteFiles, remoteFile{
Title: cleanTitle(remoteFilePath),
FullPath: remoteFilePath,
FileInfo: walker.Stat(),
Dir: true,
RemoteFiles: rmf,
})
i++
}

continue
}

if filepath.Ext(remoteFilePath) == mkv {
remoteFiles = append(remoteFiles, remoteFile{
Title: cleanTitle(remoteFilePath),
FullPath: remoteFilePath,
FileInfo: walker.Stat(),
})
i++
}
log.Fatalf("read: %v", err)
}
defer f.Close()

urlFormat := "http://www.omdbapi.com/?s=%s"
for i, v := range remoteFiles {
// fmt.Println(v.title)
// fmt.Println(v.fullPath)
url := fmt.Sprintf(urlFormat, url.QueryEscape(v.Title))
// fmt.Printf("making request to %s\n", url)
resp, err := http.Get(url)
if err != nil {
log.Printf("error fetching movie: %v\n", err)
continue
}

apiResp := apiResponse{}
json.NewDecoder(resp.Body).Decode(&apiResp)
resp.Body.Close()

if len(apiResp.Search) > 0 {
// fmt.Println(apiResp.Search[0])
remoteFiles[i].ApiMovie = apiResp.Search[0]
}
}

apiMatches := make([]remoteFile, 0, len(remoteFiles))
for _, v := range remoteFiles {
if v.ApiMovie.Poster != "" {
apiMatches = append(apiMatches, v)
}
apiMatches := []remoteFile{}
if err := json.NewDecoder(f).Decode(&apiMatches); err != nil {
log.Fatalf("decode: %v", err)
}

fmt.Println(apiMatches)

http.HandleFunc("/", func(m []remoteFile) http.HandlerFunc {
http.HandleFunc("/api/v0/movies", func(m []remoteFile) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
Expand All @@ -164,6 +66,26 @@ func main() {
}
}(apiMatches))

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
index, err := os.Open("index.html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer index.Close()
http.ServeContent(w, r, "index", time.Now(), index)
})

http.HandleFunc("/script.js", func(w http.ResponseWriter, r *http.Request) {
script, err := os.Open("script.js")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer script.Close()
http.ServeContent(w, r, "script", time.Now(), script)
})

port := "8080"
log.Printf("starting listener on port %s", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
Expand Down Expand Up @@ -256,3 +178,114 @@ func cleanTitle(filename string) string {
}
return strings.TrimSpace(strings.Join(parts, " "))
}

func getRemoteFiles(host, user, password, dir string) []remoteFile {
pair, err := dialSSHSFTP(host, &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
})
if err != nil {
log.Fatal(err)
}

remoteFiles := []remoteFile{}

walker := pair.sftpc.Walk(dir)
i := 0
for walker.Step() {
if err := walker.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
if i == 10 {
break
}
remoteFilePath := walker.Path()
if remoteFilePath == dir {
continue
}
// Make worker pool that searches the movie api for the titles

fi := walker.Stat()
if fi.IsDir() {
// We will read the contents and put them in the
// struct, but we aren't going to return individual
// files through the API.
walker.SkipDir()

fileInfos, err := pair.sftpc.ReadDir(remoteFilePath)
if err != nil {
log.Printf("error reading dir %s, skipping\n", remoteFilePath)
continue
}

// Should I check for .mkv in here and ditch the whole dir if it doesn't have a video in it?
// Probably since that's what I'm doing for the bare files..
rmf := make([]remoteFile, len(fileInfos), len(fileInfos))
var videoDir bool
for j, fileInfo := range fileInfos {
if filepath.Ext(remoteFilePath) == mkv {
videoDir = true
}
rmf[j] = remoteFile{
Title: filepath.Base(fileInfo.Name()),
FullPath: filepath.Join(remoteFilePath, fileInfo.Name()),
FileInfo: fileInfo,
}
}
if videoDir {
remoteFiles = append(remoteFiles, remoteFile{
Title: cleanTitle(remoteFilePath),
FullPath: remoteFilePath,
FileInfo: walker.Stat(),
Dir: true,
RemoteFiles: rmf,
})
i++
}

continue
}

if filepath.Ext(remoteFilePath) == mkv {
remoteFiles = append(remoteFiles, remoteFile{
Title: cleanTitle(remoteFilePath),
FullPath: remoteFilePath,
FileInfo: walker.Stat(),
})
i++
}
}

urlFormat := "http://www.omdbapi.com/?s=%s"
for i, v := range remoteFiles {
// fmt.Println(v.title)
// fmt.Println(v.fullPath)
url := fmt.Sprintf(urlFormat, url.QueryEscape(v.Title))
// fmt.Printf("making request to %s\n", url)
resp, err := http.Get(url)
if err != nil {
log.Printf("error fetching movie: %v\n", err)
continue
}

apiResp := apiResponse{}
json.NewDecoder(resp.Body).Decode(&apiResp)
resp.Body.Close()

if len(apiResp.Search) > 0 {
// fmt.Println(apiResp.Search[0])
remoteFiles[i].ApiMovie = apiResp.Search[0]
}
}

apiMatches := make([]remoteFile, 0, len(remoteFiles))
for _, v := range remoteFiles {
if v.ApiMovie.Poster != "" {
apiMatches = append(apiMatches, v)
}
}
return apiMatches
}
33 changes: 33 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<html>

<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://unpkg.com/tachyons@4.5.3/css/tachyons.min.css"/>
</head>

<body>
<div style="width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; color: #9A9A9A; font-family: &#39;Source Sans Pro&#39;;">
<div style="font-size: 3em;">Building your project!</div>
<img src="/_reactor/waiting.gif">
<div style="font-size: 1em">With new projects, I need a bunch of extra time to download packages.</div>
</div>
</body>

<!-- Fonts and external JS and styles are available, I've put Ace for example -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.4/ace.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.4/theme-chrome.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.4/worker-lua.js"></script>

<!-- Put the name of your app here (my sources place in `src` forder) -->
<script type="text/javascript" src="/_compile/src/main.elm"></script>

<!-- Removes splash and starts elm app. -->
<script type="text/javascript">
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
runElmProgram();
</script>

</html>
44 changes: 36 additions & 8 deletions main.elm → src/main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,47 @@ update msg model =
-- View
view : Model -> Html Msg
view model =
div [] (List.map filmView model)
div [
classList [
("cf", True),
("pa2", True)
]
] (List.map filmView model)

filmView : ApiResponse -> Html msg
filmView resp =
let
movie = resp.apiMovie
in
div []
[ img [ src movie.poster ] []
, h1 [] [ text movie.title ]
, div []
[ p [] [ text movie.kind ]
, p [] [ text movie.year ]
div [
classList [
("fl", True),
("w-50", False),
("pa2", True),
("w-20", True),
("w-w-20-l", True)
]
]
[ img [
src movie.poster,
classList [
("db", True),
("w-100", True),
("outline", True),
("black-10", True),
("dim", True)
]
] []
, dl [
classList [
("mt2", True),
("f6", True),
("lh-copy", True)
]
] [
dt [ class "m10 black truncate w-100" ] [ text movie.title ],
dt [ class "m10 black truncate w-100" ] [ text movie.year ],
dt [ class "m10 black truncate w-100" ] [ text movie.kind ]
]
]

Expand All @@ -76,7 +104,7 @@ subscriptions model =
searchApi : Cmd Msg
searchApi =
let
url = "http://localhost:8080"
url = "http://localhost:8080/api/v0/movies"
in
Task.perform FetchFail FetchSucceed (Http.get decodeApiResponse url)

Expand Down

0 comments on commit 7576afc

Please sign in to comment.