Skip to content

Commit

Permalink
feat: initial implementation for mods download
Browse files Browse the repository at this point in the history
  • Loading branch information
tboerger committed May 4, 2022
1 parent eaf6c28 commit 56cdcaa
Show file tree
Hide file tree
Showing 10 changed files with 458 additions and 59 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ The following sections list the changes for unreleased.

## Summary

* Chg #1: Initial release of basic version
* Chg #3: Initial release of basic version

## Details

* Change #1: Initial release of basic version
* Change #3: Initial release of basic version

Just prepared an initial basic version which could be released to the public.

https://github.com/webhippie/cursecli/issues/1
https://github.com/webhippie/cursecli/issues/3


2 changes: 1 addition & 1 deletion changelog/unreleased/initial-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ Change: Initial release of basic version

Just prepared an initial basic version which could be released to the public.

https://github.com/webhippie/cursecli/issues/1
https://github.com/webhippie/cursecli/issues/3
25 changes: 18 additions & 7 deletions pkg/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ func Run() error {
Name: "cursecli",
Version: version.String,
Usage: "Commandline client for Curseforge",
Authors: authorList(),
Flags: globalFlags(cfg),
Commands: globalCommands(cfg),
Authors: AuthorList(),
Flags: GlobalFlags(cfg),
Before: GlobalBefore(cfg),
Commands: GlobalCmds(cfg),
}

cli.HelpFlag = &cli.BoolFlag{
Expand All @@ -36,7 +37,8 @@ func Run() error {
return app.Run(os.Args)
}

func authorList() []*cli.Author {
// AuthorList defines the list of authors.
func AuthorList() []*cli.Author {
return []*cli.Author{
{
Name: "Thomas Boerger",
Expand All @@ -45,7 +47,8 @@ func authorList() []*cli.Author {
}
}

func globalFlags(cfg *config.Config) []cli.Flag {
// GlobalFlags defines the list of global flags.
func GlobalFlags(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "log-level",
Expand All @@ -71,8 +74,16 @@ func globalFlags(cfg *config.Config) []cli.Flag {
}
}

func globalCommands(cfg *config.Config) []*cli.Command {
// GlobalBefore defines a global hook for setup.
func GlobalBefore(cfg *config.Config) cli.BeforeFunc {
return func(c *cli.Context) error {
return setupLogger(cfg)
}
}

// GlobalCmds defines the global commands.
func GlobalCmds(cfg *config.Config) []*cli.Command {
return []*cli.Command{
Download(cfg),
ManifestCmd(cfg),
}
}
48 changes: 0 additions & 48 deletions pkg/command/download.go

This file was deleted.

120 changes: 120 additions & 0 deletions pkg/command/manifest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package command

import (
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2"
"github.com/webhippie/cursecli/pkg/config"
"github.com/webhippie/cursecli/pkg/forgesvc"
"github.com/webhippie/cursecli/pkg/manifest"
)

// ManifestCmd provides the sub-command manifest.
func ManifestCmd(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "manifest",
Usage: "Manifest related commands",
Flags: ManifestFlags(cfg),
Subcommands: ManifestCmds(cfg),
}
}

// ManifestFlags defines the flags for the manifest sub-command.
func ManifestFlags(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "manifest",
Value: "manifest.json",
Usage: "Path to manifest to parse",
EnvVars: []string{"CURSECLI_MANIFEST"},
Destination: &cfg.General.Manifest,
},
}
}

// ManifestCmds defines the sub-commands for the manifest command.
func ManifestCmds(cfg *config.Config) []*cli.Command {
return []*cli.Command{
ManifestDownloadCmd(cfg),
}
}

// ManifestDownloadCmd provides the sub-command manifest download.
func ManifestDownloadCmd(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "download",
Usage: "Download related commands",
Flags: ManifestDownloadFlags(cfg),
Subcommands: ManifestDownloadCmds(cfg),
}
}

// ManifestDownloadFlags defines the flags for the manifest download sub-command.
func ManifestDownloadFlags(cfg *config.Config) []cli.Flag {
return []cli.Flag{}
}

// ManifestDownloadCmds defines the sub-commands for the manifest download command.
func ManifestDownloadCmds(cfg *config.Config) []*cli.Command {
return []*cli.Command{
ManifestDownloadModsCmd(cfg),
}
}

// ManifestDownloadModsCmd provides the sub-command manifest download mods.
func ManifestDownloadModsCmd(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "mods",
Usage: "Download mods defined within manifest",
Flags: ManifestDownloadModsFlags(cfg),
Action: ManifestDownloadModsAction(cfg),
}
}

// ManifestDownloadModsFlags defines the flags for the manifest download mods sub-command.
func ManifestDownloadModsFlags(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "path",
Value: "mods/",
Usage: "Path to download destination",
EnvVars: []string{"CURSECLI_PATH", "CURSECLI_DOWNLOAD_MODS_PATH"},
Destination: &cfg.General.Path,
},
}
}

// ManifestDownloadModsAction implements the action for the manifest download mods command.
func ManifestDownloadModsAction(cfg *config.Config) cli.ActionFunc {
return func(c *cli.Context) error {
m, err1 := manifest.New(
manifest.WithPath(c.String("manifest")),
)

if err1 != nil {
log.Error().
Err(err1).
Msg("Failed to parse manifest")

return err1
}

f, err2 := forgesvc.New(
forgesvc.WithPath(c.String("path")),
forgesvc.WithManifest(m),
)

if err2 != nil {
log.Error().
Err(err2).
Msg("Failed to initalize client")

return err2
}

if err := f.DownloadManifest(); err != nil {
return err
}

return nil
}
}
130 changes: 130 additions & 0 deletions pkg/forgesvc/forgesvc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package forgesvc

import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"

"github.com/rs/zerolog/log"
"github.com/webhippie/cursecli/pkg/manifest"
)

const (
downloadURL = "https://addons-ecs.forgesvc.net/api/v2/addon/%d/file/%d"
)

// Forgesvc defines the forgesvc itself.
type Forgesvc struct {
HTTPClient *http.Client
Path string
Manifest manifest.Manifest
}

// New parses and prepares a manifest definition.
func New(opts ...Option) (*Forgesvc, error) {
sopts := newOptions(opts...)

return &Forgesvc{
HTTPClient: sopts.HTTPClient,
Path: sopts.Path,
Manifest: sopts.Manifest,
}, nil
}

// DownloadManifest downloads all mods defined within a manifest.
func (f *Forgesvc) DownloadManifest() error {
if err := os.MkdirAll(f.Path, os.ModePerm); err != nil {
log.Error().
Err(err).
Str("path", f.Path).
Msg("Failed to create mod directory")

return err
}

for _, file := range f.Manifest.Files {
resp, err := f.HTTPClient.Get(
fmt.Sprintf(
downloadURL,
file.ProjectID,
file.FileID,
),
)

if err != nil {
log.Error().
Err(err).
Int("project", file.ProjectID).
Int("file", file.FileID).
Msg("Failed to fetch mod details")

return err
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)

if err != nil {
log.Error().
Err(err).
Int("project", file.ProjectID).
Int("file", file.FileID).
Msg("Failed to read mod details")

return err
}

download := File{}

if err := json.Unmarshal(body, &download); err != nil {
log.Error().
Err(err).
Int("project", file.ProjectID).
Int("file", file.FileID).
Msg("Failed to parse mod details")

return err
}

if err := f.downloadFile(
download.Name,
download.URL,
); err != nil {
return err
}

log.Info().
Int("project", file.ProjectID).
Int("file", file.FileID).
Str("name", download.Name).
Msg("Successfully downloaded mod")
}

return nil
}

func (f *Forgesvc) downloadFile(name, url string) error {
resp, err := f.HTTPClient.Get(
url,
)

if err != nil {
return err
}

defer resp.Body.Close()
out, err := os.Create(filepath.Join(f.Path, name))

if err != nil {
return err
}

defer out.Close()
_, err = io.Copy(out, resp.Body)

return err
}
Loading

0 comments on commit 56cdcaa

Please sign in to comment.