Skip to content

Commit

Permalink
Add check command
Browse files Browse the repository at this point in the history
  • Loading branch information
RadhiFadlillah committed Sep 21, 2019
1 parent 0bf5772 commit 2eb6415
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 0 deletions.
141 changes: 141 additions & 0 deletions internal/cmd/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package cmd

import (
"fmt"
"net/http"
"sort"
"sync"
"time"

"github.com/go-shiori/shiori/internal/database"
"github.com/go-shiori/shiori/internal/model"
"github.com/spf13/cobra"
)

func checkCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "check",
Short: "Find bookmarked sites that no longer exists on the internet",
Long: "Check all bookmarks and find bookmarked sites that no longer exists on the internet. " +
"It might take a long time depending on how many bookmarks that you have and want to check. " +
"If there are no arguments, it will check ALL of your bookmarks.",
Run: checkHandler,
}

cmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt and check ALL bookmarks")

return cmd
}

func checkHandler(cmd *cobra.Command, args []string) {
// Parse flags
skipConfirm, _ := cmd.Flags().GetBool("yes")

// If no arguments (i.e all bookmarks going to be checked), confirm to user
if len(args) == 0 && !skipConfirm {
confirmCheck := ""
fmt.Print("Check ALL bookmarks? (y/N): ")
fmt.Scanln(&confirmCheck)

if confirmCheck != "y" {
fmt.Println("No bookmarks checked")
return
}
}

// Convert args to ids
ids, err := parseStrIndices(args)
if err != nil {
cError.Printf("Failed to parse args: %v\n", err)
return
}

// Fetch bookmarks from database
filterOptions := database.GetBookmarksOptions{IDs: ids}
bookmarks, err := db.GetBookmarks(filterOptions)
if err != nil {
cError.Printf("Failed to get bookmarks: %v\n", err)
return
}

// Create HTTP client
httpClient := &http.Client{Timeout: time.Minute}

// Test each bookmark item
unreachableIDs := []int{}

wg := sync.WaitGroup{}
chDone := make(chan struct{})
chProblem := make(chan int, 10)
chMessage := make(chan interface{}, 10)
semaphore := make(chan struct{}, 10)

for i, book := range bookmarks {
wg.Add(1)

go func(i int, book model.Bookmark) {
// Make sure to finish the WG
defer wg.Done()

// Register goroutine to semaphore
semaphore <- struct{}{}
defer func() {
<-semaphore
}()

// Ping bookmark's URL
_, err := httpClient.Get(book.URL)
if err != nil {
chProblem <- book.ID
chMessage <- fmt.Errorf("Failed to reach %s: %v", book.URL, err)
return
}

// Send success message
chMessage <- fmt.Sprintf("Reached %s", book.URL)
}(i, book)
}

// Watch messages from channels
go func(nBookmark int) {
logIndex := 0

for {
select {
case <-chDone:
cInfo.Println("Check finished")
return
case id := <-chProblem:
unreachableIDs = append(unreachableIDs, id)
case msg := <-chMessage:
logIndex++

switch msg.(type) {
case error:
cError.Printf("[%d/%d] %v\n", logIndex, nBookmark, msg)
case string:
cInfo.Printf("[%d/%d] %s\n", logIndex, nBookmark, msg)
}
}
}
}(len(bookmarks))

// Wait until all download finished
wg.Wait()
close(chDone)

// Print the unreachable bookmarks
fmt.Println()

if len(unreachableIDs) == 0 {
cInfo.Println("All bookmarks is reachable.")
} else {
sort.Ints(unreachableIDs)

cError.Println("Encountered some unreachable bookmarks:")
for _, id := range unreachableIDs {
cError.Printf("%d ", id)
}
fmt.Println()
}
}
1 change: 1 addition & 0 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func ShioriCmd() *cobra.Command {
exportCmd(),
pocketCmd(),
serveCmd(),
checkCmd(),
)

return rootCmd
Expand Down

0 comments on commit 2eb6415

Please sign in to comment.