Skip to content

Commit fbea541

Browse files
committed
refactor(json-parser): refacted encryption grouping and added tests
1 parent e96c10f commit fbea541

File tree

4 files changed

+309
-73
lines changed

4 files changed

+309
-73
lines changed

examples/json_server/main.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"log"
6+
"net/http"
7+
8+
packlit "github.com/m4urici0gm/packlit/pkg"
9+
)
10+
11+
func main() {
12+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
13+
if r.Method != http.MethodPost {
14+
w.WriteHeader(http.StatusMethodNotAllowed)
15+
return
16+
}
17+
18+
var req packlit.PackagerOptions
19+
decoder := json.NewDecoder(r.Body)
20+
decoder.DisallowUnknownFields()
21+
if err := decoder.Decode(&req); err != nil {
22+
http.Error(w, err.Error(), http.StatusBadRequest)
23+
return
24+
}
25+
26+
sp, err := packlit.BuildFromJSON(req)
27+
if err != nil {
28+
http.Error(w, err.Error(), http.StatusBadRequest)
29+
return
30+
}
31+
32+
command, err := sp.PreviewCommand()
33+
if err != nil {
34+
http.Error(w, err.Error(), http.StatusInternalServerError)
35+
return
36+
}
37+
38+
w.Header().Set("Content-Type", "application/json")
39+
_ = json.NewEncoder(w).Encode(map[string]interface{}{
40+
"command_preview": command,
41+
})
42+
})
43+
44+
log.Println("Starting server on :8080. POST /")
45+
log.Fatal(http.ListenAndServe(":8080", nil))
46+
}

pkg/generic_flags.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package packlit
2+
3+
import "fmt"
4+
5+
// Generic flag types for extensibility
6+
type GenericKeyValueOption struct {
7+
Key string
8+
Value string
9+
}
10+
11+
func (g GenericKeyValueOption) Validate() error { return nil }
12+
func (g GenericKeyValueOption) Parse() string { return fmt.Sprintf("%s=%s", g.Key, g.Value) }
13+
14+
type GenericRawFlag string
15+
16+
func (g GenericRawFlag) Validate() error { return nil }
17+
func (g GenericRawFlag) Parse() string { return string(g) }
18+
19+
type GenericKeyValueFlag struct {
20+
Key string
21+
Value string
22+
}
23+
24+
func (g GenericKeyValueFlag) Validate() error {
25+
if g.Key == "" {
26+
return fmt.Errorf("flag key cannot be empty")
27+
}
28+
return nil
29+
}
30+
31+
func (g GenericKeyValueFlag) Parse() string { return fmt.Sprintf("--%s=%s", g.Key, g.Value) }
32+
33+
type GenericBoolFlag string
34+
35+
func (g GenericBoolFlag) Validate() error {
36+
if string(g) == "" {
37+
return fmt.Errorf("flag name cannot be empty")
38+
}
39+
return nil
40+
}
41+
42+
func (g GenericBoolFlag) Parse() string { return "--" + string(g) }

pkg/jsonio.go

Lines changed: 73 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@ type PackagerOptions struct {
2626
Manifest *ManifestFlags `json:"manifest,omitempty"`
2727
HTTP *HttpFlags `json:"http,omitempty"`
2828
HLS *HlsFlags `json:"hls,omitempty"`
29-
Crypto *CryptoFlags `json:"crypto,omitempty"`
30-
Protection *ProtectionFlags `json:"protection,omitempty"`
31-
RawKey *RawKeyFlags `json:"raw_key,omitempty"`
32-
Widevine *WideVineFlags `json:"widevine,omitempty"`
33-
Playready *PlayReadyFlags `json:"playready,omitempty"`
29+
Encryption *EncryptionFlags `json:"encryption,omitempty"`
3430
}
3531

3632
// Flag configuration structs
@@ -60,21 +56,21 @@ type MuxerFlags struct {
6056
}
6157

6258
type MpdFlags struct {
63-
OutputMediaInfo bool `json:"output_media_info,omitempty"`
64-
MpdOutput string `json:"mpd_output,omitempty"`
65-
BaseUrls []string `json:"base_urls,omitempty"`
66-
GenerateStaticLiveMpd bool `json:"generate_static_live_mpd,omitempty"`
67-
AllowApproximateSegmentTimeline bool `json:"allow_approximate_segment_timeline,omitempty"`
68-
DumpStreamInfo bool `json:"dump_stream_info,omitempty"`
69-
MinBufferTime float32 `json:"min_buffer_time,omitempty"`
70-
MinimumUpdatePeriod float32 `json:"minimum_update_period,omitempty"`
71-
SuggestedPresentationDelay float32 `json:"suggested_presentation_delay,omitempty"`
72-
UtcTimings []string `json:"utc_timings,omitempty"`
73-
GenerateDashIfIopCompliantMpd bool `json:"generate_dash_if_iop_compliant_mpd,omitempty"`
74-
AllowCodecSwitching bool `json:"allow_codec_switching,omitempty"`
75-
IncludeMsprProForPlayReady bool `json:"include_mspr_pro_for_playready,omitempty"`
76-
DashForceSegmentList bool `json:"dash_force_segment_list,omitempty"`
77-
LowLatencyDashMode bool `json:"low_latency_dash_mode,omitempty"`
59+
OutputMediaInfo bool `json:"output_media_info,omitempty"`
60+
MpdOutput string `json:"mpd_output,omitempty"`
61+
BaseUrls []string `json:"base_urls,omitempty"`
62+
GenerateStaticLiveMpd bool `json:"generate_static_live_mpd,omitempty"`
63+
AllowApproximateSegmentTimeline bool `json:"allow_approximate_segment_timeline,omitempty"`
64+
DumpStreamInfo bool `json:"dump_stream_info,omitempty"`
65+
MinBufferTime float32 `json:"min_buffer_time,omitempty"`
66+
MinimumUpdatePeriod float32 `json:"minimum_update_period,omitempty"`
67+
SuggestedPresentationDelay float32 `json:"suggested_presentation_delay,omitempty"`
68+
UtcTimings map[string]string `json:"utc_timings,omitempty"`
69+
GenerateDashIfIopCompliantMpd bool `json:"generate_dash_if_iop_compliant_mpd,omitempty"`
70+
AllowCodecSwitching bool `json:"allow_codec_switching,omitempty"`
71+
IncludeMsprProForPlayReady bool `json:"include_mspr_pro_for_playready,omitempty"`
72+
DashForceSegmentList bool `json:"dash_force_segment_list,omitempty"`
73+
LowLatencyDashMode bool `json:"low_latency_dash_mode,omitempty"`
7874
}
7975

8076
type ManifestFlags struct {
@@ -106,24 +102,34 @@ type HlsFlags struct {
106102
CreateSessionKeys bool `json:"create_session_keys,omitempty"`
107103
}
108104

109-
type CryptoFlags struct {
110-
CryptByteBlock int `json:"crypt_byte_block,omitempty"`
111-
ProtectionScheme string `json:"protection_scheme,omitempty"`
112-
SkipByteBlock int `json:"skip_byte_block,omitempty"`
113-
Vp9SubsampleEncryption bool `json:"vp9_subsample_encryption,omitempty"`
114-
PlayreadyExtraHeaderData string `json:"playready_extra_header_data,omitempty"`
105+
type EncryptionFlags struct {
106+
CryptByteBlock int `json:"crypt_byte_block,omitempty"`
107+
ProtectionScheme string `json:"protection_scheme,omitempty"`
108+
ProtectionSystems []string `json:"protection_systems,omitempty"`
109+
SkipByteBlock int `json:"skip_byte_block,omitempty"`
110+
Vp9SubsampleEncryption bool `json:"vp9_subsample_encryption,omitempty"`
111+
PlayreadyExtraHeaderData string `json:"playready_extra_header_data,omitempty"`
112+
RawKey *RawKeyFlags `json:"raw_key,omitempty"`
113+
Widevine *WideVineFlags `json:"widevine,omitempty"`
114+
Playready *PlayReadyFlags `json:"playready,omitempty"`
115115
}
116116

117-
type ProtectionFlags struct {
118-
ProtectionSystems []string `json:"protection_systems,omitempty"`
117+
type RawKeyInfo struct {
118+
Label string `json:"label"`
119+
KeyId string `json:"key_id"`
120+
Key string `json:"key"`
121+
}
122+
123+
func (r *RawKeyInfo) String() string {
124+
return fmt.Sprintf("label=%s:key_id=%s:key=%s", r.Label, r.KeyId, r.Key)
119125
}
120126

121127
type RawKeyFlags struct {
122-
EnableEncryption bool `json:"enable_raw_key_encryption,omitempty"`
123-
EnableDecryption bool `json:"enable_raw_key_decryption,omitempty"`
124-
Keys []string `json:"keys,omitempty"`
125-
Iv string `json:"iv,omitempty"`
126-
Pssh string `json:"pssh,omitempty"`
128+
EnableEncryption bool `json:"enable_raw_key_encryption,omitempty"`
129+
EnableDecryption bool `json:"enable_raw_key_decryption,omitempty"`
130+
Keys []RawKeyInfo `json:"keys,omitempty"`
131+
Iv string `json:"iv,omitempty"`
132+
Pssh string `json:"pssh,omitempty"`
127133
}
128134

129135
type WideVineFlags struct {
@@ -311,7 +317,15 @@ func (m *MPDFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
311317
flagFns = append(flagFns, WithSuggestedPresentationDelayFlag(m.flags.SuggestedPresentationDelay))
312318
}
313319
if len(m.flags.UtcTimings) > 0 {
314-
flagFns = append(flagFns, WithUtCTimingsFlag(m.flags.UtcTimings))
320+
// Convert map to comma-separated scheme_id_uri=value pairs
321+
timingPairs := make([]string, 0, len(m.flags.UtcTimings))
322+
for schemeIdUri, value := range m.flags.UtcTimings {
323+
if schemeIdUri == "" {
324+
return nil, fmt.Errorf("empty scheme_id_uri found in utc_timings")
325+
}
326+
timingPairs = append(timingPairs, fmt.Sprintf("%s=%s", schemeIdUri, value))
327+
}
328+
flagFns = append(flagFns, WithUtCTimingsFlag(timingPairs))
315329
}
316330
if m.flags.GenerateDashIfIopCompliantMpd {
317331
flagFns = append(flagFns, WithGenerateDashIfIopCompliantMpdFlag())
@@ -467,18 +481,18 @@ func (h *HLSFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
467481
return flagFns, nil
468482
}
469483

470-
// CryptoFlagsProcessor processes crypto flags
471-
type CryptoFlagsProcessor struct {
472-
flags *CryptoFlags
484+
// EncryptionFlagsProcessor processes crypto flags
485+
type EncryptionFlagsProcessor struct {
486+
flags *EncryptionFlags
473487
}
474488

475-
var _ FlagProcessor = (*CryptoFlagsProcessor)(nil)
489+
var _ FlagProcessor = (*EncryptionFlagsProcessor)(nil)
476490

477-
func NewCryptoFlagsProcessor(flags *CryptoFlags) *CryptoFlagsProcessor {
478-
return &CryptoFlagsProcessor{flags: flags}
491+
func NewEncryptionFlagsProcessor(flags *EncryptionFlags) *EncryptionFlagsProcessor {
492+
return &EncryptionFlagsProcessor{flags: flags}
479493
}
480494

481-
func (c *CryptoFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
495+
func (c *EncryptionFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
482496
if c.flags == nil {
483497
return nil, nil
484498
}
@@ -494,6 +508,9 @@ func (c *CryptoFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
494508
if c.flags.ProtectionScheme != "" {
495509
flagFns = append(flagFns, WithProtectionSchemeFlag(c.flags.ProtectionScheme))
496510
}
511+
if len(c.flags.ProtectionSystems) > 0 {
512+
flagFns = append(flagFns, WithProtectionSystemsFlag(c.flags.ProtectionSystems))
513+
}
497514
if c.flags.SkipByteBlock != 0 {
498515
if c.flags.SkipByteBlock < 0 {
499516
return nil, fmt.Errorf("skip_byte_block cannot be negative: %d", c.flags.SkipByteBlock)
@@ -510,31 +527,6 @@ func (c *CryptoFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
510527
return flagFns, nil
511528
}
512529

513-
// ProtectionFlagsProcessor processes protection flags
514-
type ProtectionFlagsProcessor struct {
515-
flags *ProtectionFlags
516-
}
517-
518-
var _ FlagProcessor = (*ProtectionFlagsProcessor)(nil)
519-
520-
func NewProtectionFlagsProcessor(flags *ProtectionFlags) *ProtectionFlagsProcessor {
521-
return &ProtectionFlagsProcessor{flags: flags}
522-
}
523-
524-
func (p *ProtectionFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
525-
if p.flags == nil {
526-
return nil, nil
527-
}
528-
529-
var flagFns []ShakaFlagFn
530-
531-
if len(p.flags.ProtectionSystems) > 0 {
532-
flagFns = append(flagFns, WithProtectionSystemsFlag(p.flags.ProtectionSystems))
533-
}
534-
535-
return flagFns, nil
536-
}
537-
538530
// RawKeyFlagsProcessor processes raw key flags
539531
type RawKeyFlagsProcessor struct {
540532
flags *RawKeyFlags
@@ -560,7 +552,12 @@ func (r *RawKeyFlagsProcessor) ProcessFlags() ([]ShakaFlagFn, error) {
560552
flagFns = append(flagFns, WithEnableRawKeyDecryptionFlag())
561553
}
562554
if len(r.flags.Keys) > 0 {
563-
flagFns = append(flagFns, WithKeysFlag(r.flags.Keys))
555+
// Validate and convert key info structs to formatted strings
556+
keyStrings := make([]string, 0, len(r.flags.Keys))
557+
for _, keyInfo := range r.flags.Keys {
558+
keyStrings = append(keyStrings, keyInfo.String())
559+
}
560+
flagFns = append(flagFns, WithKeysFlag(keyStrings))
564561
}
565562
if r.flags.Iv != "" {
566563
flagFns = append(flagFns, WithIvFlag(r.flags.Iv))
@@ -703,11 +700,14 @@ func (pb *PackagerJsonBuilder) Build() (*ShakaPackager, error) {
703700
NewManifestFlagsProcessor(pb.options.Manifest),
704701
NewHTTPFlagsProcessor(pb.options.HTTP),
705702
NewHLSFlagsProcessor(pb.options.HLS),
706-
NewCryptoFlagsProcessor(pb.options.Crypto),
707-
NewProtectionFlagsProcessor(pb.options.Protection),
708-
NewRawKeyFlagsProcessor(pb.options.RawKey),
709-
NewWideVineFlagsProcessor(pb.options.Widevine),
710-
NewPlayReadyFlagsProcessor(pb.options.Playready),
703+
NewEncryptionFlagsProcessor(pb.options.Encryption),
704+
}
705+
706+
// Add encryption-related processors if encryption options are provided
707+
if pb.options.Encryption != nil {
708+
processors = append(processors, NewRawKeyFlagsProcessor(pb.options.Encryption.RawKey))
709+
processors = append(processors, NewWideVineFlagsProcessor(pb.options.Encryption.Widevine))
710+
processors = append(processors, NewPlayReadyFlagsProcessor(pb.options.Encryption.Playready))
711711
}
712712

713713
var allFlags []ShakaFlagFn
@@ -770,7 +770,7 @@ func UnmarshalFlagsFromJSON(data []byte) (PackagerOptions, error) {
770770
}
771771

772772
// BuildFromJSON is the main entry point with improved error handling
773-
func BuildShakaPackagerFromJSON(req PackagerOptions) (*ShakaPackager, error) {
773+
func BuildFromJSON(req PackagerOptions) (*ShakaPackager, error) {
774774
builder := NewPackagerJsonBuilder(&req)
775775
return builder.Build()
776776
}

0 commit comments

Comments
 (0)