| package modportal |
| |
| import ( |
| "context" |
| "encoding/json" |
| "fmt" |
| "io" |
| "net/http" |
| "net/url" |
| |
| "google.golang.org/grpc/codes" |
| "google.golang.org/grpc/status" |
| ) |
| |
| type Mod struct { |
| Name string `json:"name"` |
| Releases []Release `json:"releases"` |
| } |
| |
| type Release struct { |
| DownloadURL string `json:"download_url"` |
| FileName string `json:"file_name"` |
| Info InfoJSON `json:"info_json"` |
| ReleasedAt string `json:"released_at"` |
| SHA1 string `json:"sha1"` |
| Version string `json:"version"` |
| } |
| |
| type InfoJSON struct { |
| Dependencies []string `json:"dependencies"` |
| FactorioVersion string `json:"factorio_json"` |
| } |
| |
| func GetMod(ctx context.Context, name string) (*Mod, error) { |
| url := fmt.Sprintf("https://mods.factorio.com/api/mods/%s", url.PathEscape(name)) |
| |
| req, err := http.NewRequest("GET", url, nil) |
| if err != nil { |
| return nil, status.Errorf(codes.Internal, "NewRequest(%q): %v", url, err) |
| } |
| |
| req = req.WithContext(ctx) |
| res, err := http.DefaultClient.Do(req) |
| if err != nil { |
| return nil, status.Errorf(codes.Unavailable, "Do(req{%q}): %v", url, err) |
| } |
| defer res.Body.Close() |
| |
| if res.StatusCode != 200 { |
| return nil, status.Errorf(codes.Unavailable, "mod portal responded with code: %d", res.StatusCode) |
| } |
| |
| mod := &Mod{} |
| err = json.NewDecoder(res.Body).Decode(mod) |
| if err != nil { |
| return nil, status.Errorf(codes.Internal, "could not decode mod portal JSON: %v", err) |
| } |
| |
| return mod, nil |
| } |
| |
| func (m *Mod) ReleaseBySHA1(sha1 string) *Release { |
| for _, r := range m.Releases { |
| if r.SHA1 == sha1 { |
| return &r |
| } |
| } |
| return nil |
| } |
| |
| func (m *Mod) ReleaseByVersion(version string) *Release { |
| for _, r := range m.Releases { |
| if r.Version == version { |
| return &r |
| } |
| } |
| return nil |
| } |
| |
| func (r *Release) Download(ctx context.Context, username, token string) (io.ReadCloser, error) { |
| url := fmt.Sprintf("https://mods.factorio.com/%s?username=%s&token=%s", r.DownloadURL, username, token) |
| req, err := http.NewRequest("GET", url, nil) |
| if err != nil { |
| return nil, status.Errorf(codes.Internal, "NewRequest(%q): %v", url, err) |
| } |
| |
| req = req.WithContext(ctx) |
| res, err := http.DefaultClient.Do(req) |
| if err != nil { |
| return nil, status.Errorf(codes.Unavailable, "Do(req{%q}): %v", url, err) |
| } |
| if res.StatusCode != 200 { |
| res.Body.Close() |
| return nil, status.Errorf(codes.Unavailable, "mod portal responded with code: %d", res.StatusCode) |
| } |
| |
| return res.Body, err |
| } |