Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `internal/usage` package and `kasapi-cli usage` subcommand tree
covering the three KAS read endpoints around webspace and traffic
counters: `usage space` (`get_space`) lists per-account webspace
totals with a usage ratio; `usage space-detail [--directory PATH]`
(`get_space_usage`) reports per-directory file counts and byte sums;
`usage traffic [--year Y --month M]` (`get_traffic`) returns the
monthly summary plus per-day rows. The decoder maps the get_traffic
Map keyed by `0` / `01..31` into a slice (summary first, then days),
treats `xsi:nil` FTP fields as zero, and parses the xsd:string-encoded
byte counts into `int64` so 9-digit values survive on 32-bit
platforms. Closes #10.

- `internal/session` persistent session-token cache so a successful
KasAuth login (including 2FA via `--otp`) survives across CLI
invocations: a new `sessions.toml` next to the config file (mode
Expand Down
1 change: 1 addition & 0 deletions cmd/kasapi-cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func main() {
root.AddCommand(
cli.NewAccountCmd(opts),
cli.NewServerCmd(opts),
cli.NewUsageCmd(opts),
cli.NewConfigCmd(opts),
)
if err := root.Execute(); err != nil {
Expand Down
97 changes: 97 additions & 0 deletions internal/cli/usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package cli

import (
"github.com/spf13/cobra"

"github.com/chmmou/kasapi-cli/internal/usage"
)

// NewUsageCmd returns the "kasapi-cli usage" subcommand tree:
// space (get_space), space-detail (get_space_usage),
// traffic (get_traffic).
func NewUsageCmd(opts *RootOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "usage",
Short: "Inspect webspace and traffic counters",
}
cmd.AddCommand(
newUsageSpaceCmd(opts),
newUsageSpaceDetailCmd(opts),
newUsageTrafficCmd(opts),
)
return cmd
}

func newUsageSpaceCmd(opts *RootOptions) *cobra.Command {
return &cobra.Command{
Use: "space",
Short: "Show webspace totals per account (get_space)",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
api, err := BuildAPIClient(opts)
if err != nil {
return err
}
list, err := usage.NewClient(api).Space(cmd.Context())
if err != nil {
return APIError(err, "get_space")
}
if err := Render(cmd.OutOrStdout(), opts.Output, list); err != nil {
return UserError(err, "render")
}
return nil
},
}
}

func newUsageSpaceDetailCmd(opts *RootOptions) *cobra.Command {
var directory string
cmd := &cobra.Command{
Use: "space-detail",
Short: "Show per-directory disk usage (get_space_usage)",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
api, err := BuildAPIClient(opts)
if err != nil {
return err
}
list, err := usage.NewClient(api).SpaceUsage(cmd.Context(), directory)
if err != nil {
return APIError(err, "get_space_usage")
}
if err := Render(cmd.OutOrStdout(), opts.Output, list); err != nil {
return UserError(err, "render")
}
return nil
},
}
cmd.Flags().StringVar(&directory, "directory", "",
"directory to drill into; empty queries the document-root level")
return cmd
}

func newUsageTrafficCmd(opts *RootOptions) *cobra.Command {
var year, month int
cmd := &cobra.Command{
Use: "traffic",
Short: "Show monthly HTTP/FTP traffic (get_traffic)",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
api, err := BuildAPIClient(opts)
if err != nil {
return err
}
list, err := usage.NewClient(api).Traffic(cmd.Context(), year, month)
if err != nil {
return APIError(err, "get_traffic")
}
if err := Render(cmd.OutOrStdout(), opts.Output, list); err != nil {
return UserError(err, "render")
}
return nil
},
}
cmd.Flags().IntVar(&year, "year", 0, "calendar year (e.g. 2026); 0 = current")
cmd.Flags().IntVar(&month, "month", 0, "calendar month 1..12; 0 = current")
return cmd
}
Loading
Loading