<commit_before>package api

import (
	"archive/zip"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"net/http"
	"path"
	"path/filepath"
	"runtime"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/types"

	"github.com/inconshreveable/go-update"
	"github.com/julienschmidt/httprouter"
	"github.com/kardianos/osext"
)

// SiaConstants is a struct listing all of the constants in use.
type SiaConstants struct {
	GenesisTimestamp      types.Timestamp   `json:"genesistimestamp"`
	BlockSizeLimit        uint64            `json:"blocksizelimit"`
	BlockFrequency        types.BlockHeight `json:"blockfrequency"`
	TargetWindow          types.BlockHeight `json:"targetwindow"`
	MedianTimestampWindow uint64            `json:"mediantimestampwindow"`
	FutureThreshold       types.Timestamp   `json:"futurethreshold"`
	SiafundCount          types.Currency    `json:"siafundcount"`
	SiafundPortion        *big.Rat          `json:"siafundportion"`
	MaturityDelay         types.BlockHeight `json:"maturitydelay"`

	InitialCoinbase uint64 `json:"initialcoinbase"`
	MinimumCoinbase uint64 `json:"minimumcoinbase"`

	RootTarget types.Target `json:"roottarget"`
	RootDepth  types.Target `json:"rootdepth"`

	MaxAdjustmentUp   *big.Rat `json:"maxadjustmentup"`
	MaxAdjustmentDown *big.Rat `json:"maxadjustmentdown"`

	SiacoinPrecision types.Currency `json:"siacoinprecision"`
}

type DaemonVersion struct {
	Version string `json:"version"`
}

// UpdateInfo indicates whether an update is available, and to what
// version.
type UpdateInfo struct {
	Available bool   `json:"available"`
	Version   string `json:"version"`
}

// githubRelease represents some of the JSON returned by the GitHub release API
// endpoint. Only the fields relevant to updating are included.
type githubRelease struct {
	TagName string `json:"tag_name"`
	Assets  []struct {
		Name        string `json:"name"`
		DownloadURL string `json:"browser_download_url"`
	} `json:"assets"`
}

const (
	// The developer key is used to sign updates and other important Sia-
	// related information.
	developerKey = `-----BEGIN PUBLIC KEY-----
<KEY>
-----END PUBLIC KEY-----`
)

// fetchLatestRelease returns metadata about the most recent GitHub release.
func fetchLatestRelease() (githubRelease, error) {
	req, err := http.NewRequest("GET", "https://api.github.com/repos/NebulousLabs/Sia/releases/latest", nil)
	if err != nil {
		return githubRelease{}, err
	}
	req.Header.Set("Accept", "application/vnd.github.v3+json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return githubRelease{}, err
	}
	defer resp.Body.Close()
	var release githubRelease
	err = json.NewDecoder(resp.Body).Decode(&release)
	if err != nil {
		return githubRelease{}, err
	}
	return release, nil
}

// updateToRelease updates siad and siac to the release specified. siac is
// assumed to be in the same folder as siad.
func updateToRelease(release githubRelease) error {
	updateOpts := update.Options{
		Verifier: update.NewRSAVerifier(),
	}
	err := updateOpts.SetPublicKeyPEM([]byte(developerKey))
	if err != nil {
		// should never happen<commit_msg>introduce errEmptyUpdateResponse<commit_after>package api

import (
	"archive/zip"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"net/http"
	"path"
	"path/filepath"
	"runtime"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/types"

	"github.com/inconshreveable/go-update"
	"github.com/julienschmidt/httprouter"
	"github.com/kardianos/osext"
)

var errEmptyUpdateResponse = errors.New("API call to https://api.github.com/repos/NebulousLabs/Sia/releases/latest is returning an empty response")

// SiaConstants is a struct listing all of the constants in use.
type SiaConstants struct {
	GenesisTimestamp      types.Timestamp   `json:"genesistimestamp"`
	BlockSizeLimit        uint64            `json:"blocksizelimit"`
	BlockFrequency        types.BlockHeight `json:"blockfrequency"`
	TargetWindow          types.BlockHeight `json:"targetwindow"`
	MedianTimestampWindow uint64            `json:"mediantimestampwindow"`
	FutureThreshold       types.Timestamp   `json:"futurethreshold"`
	SiafundCount          types.Currency    `json:"siafundcount"`
	SiafundPortion        *big.Rat          `json:"siafundportion"`
	MaturityDelay         types.BlockHeight `json:"maturitydelay"`

	InitialCoinbase uint64 `json:"initialcoinbase"`
	MinimumCoinbase uint64 `json:"minimumcoinbase"`

	RootTarget types.Target `json:"roottarget"`
	RootDepth  types.Target `json:"rootdepth"`

	MaxAdjustmentUp   *big.Rat `json:"maxadjustmentup"`
	MaxAdjustmentDown *big.Rat `json:"maxadjustmentdown"`

	SiacoinPrecision types.Currency `json:"siacoinprecision"`
}

type DaemonVersion struct {
	Version string `json:"version"`
}

// UpdateInfo indicates whether an update is available, and to what
// version.
type UpdateInfo struct {
	Available bool   `json:"available"`
	Version   string `json:"version"`
}

// githubRelease represents some of the JSON returned by the GitHub release API
// endpoint. Only the fields relevant to updating are included.
type githubRelease struct {
	TagName string `json:"tag_name"`
	Assets  []struct {
		Name        string `json:"name"`
		DownloadURL string `json:"browser_download_url"`
	} `json:"assets"`
}

const (
	// The developer key is used to sign updates and other important Sia-
	// related information.
	developerKey = `-----<KEY>
-----END PUBLIC KEY-----`
)

// fetchLatestRelease returns metadata about the most recent GitHub release.
func fetchLatestRelease() (githubRelease, error) {
	req, err := http.NewRequest("GET", "https://api.github.com/repos/NebulousLabs/Sia/releases/latest", nil)
	if err != nil {
		return githubRelease{}, err
	}
	req.Header.Set("Accept", "application/vnd.github.v3+json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return githubRelease{}, err
	}
	defer resp.Body.Close()
	var release githubRelease
	err = json.NewDecoder(resp.Body).Decode(&release)
	if err != nil {
		return githubRelease{}, err
	}
	if release.TagName == "" && len(release.Assets) == 0 {
		return githubRelease{}, errEmptyUpdateResponse
	}
	return release, nil
}

// updateToRelease updates siad and siac to the release specified. siac is
// assumed to be in the same folder as siad.
func updateToRelease(release githubRelease) error {
	updateOpts := update.Options{
		Verifier: update.NewRSAVerifier(),
	}
	err := updateOpts.SetPublicKeyPEM([]byte(developerKey))
	if err != nil {
		// should never happen
{'fraction_non_alphanumeric': 0.11878453038674033, 'fraction_numerical': 0.0029158993247391037, 'mean_word_length': 4.196969696969697, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3043111', 'n_tokens_mistral': 2123, 'n_tokens_neox': 2030, 'n_words': 523}