| 55 | } |
| 56 | |
| 57 | func GetMetadataFields(subject string) ([]string, error) { |
| 58 | v1TokenCounts, v2TokenCounts := 9, 12 |
| 59 | |
| 60 | var start int |
| 61 | tokens := make([]string, 0, v2TokenCounts) |
| 62 | for i := 0; i < len(subject); i++ { |
| 63 | if subject[i] == '.' { |
| 64 | tokens = append(tokens, subject[start:i]) |
| 65 | start = i + 1 |
| 66 | } |
| 67 | } |
| 68 | tokens = append(tokens, subject[start:]) |
| 69 | // |
| 70 | // Newer server will include the domain name and account hash in the subject, |
| 71 | // and a token at the end. |
| 72 | // |
| 73 | // Old subject was: |
| 74 | // $JS.ACK.<stream>.<consumer>.<delivered>.<sseq>.<cseq>.<tm>.<pending> |
| 75 | // |
| 76 | // New subject would be: |
| 77 | // $JS.ACK.<domain>.<account hash>.<stream>.<consumer>.<delivered>.<sseq>.<cseq>.<tm>.<pending>.<a token with a random value> |
| 78 | // |
| 79 | // v1 has 9 tokens, v2 has 12, but we must not be strict on the 12th since |
| 80 | // it may be removed in the future. Also, the library has no use for it. |
| 81 | // The point is that a v2 ACK subject is valid if it has at least 11 tokens. |
| 82 | // |
| 83 | tokensLen := len(tokens) |
| 84 | // If lower than 9 or more than 9 but less than 11, report an error |
| 85 | if tokensLen < v1TokenCounts || (tokensLen > v1TokenCounts && tokensLen < v2TokenCounts-1) { |
| 86 | return nil, ErrInvalidSubjectFormat |
| 87 | } |
| 88 | if tokens[0] != "$JS" || tokens[1] != "ACK" { |
| 89 | return nil, fmt.Errorf("%w: subject should start with $JS.ACK", ErrInvalidSubjectFormat) |
| 90 | } |
| 91 | // For v1 style, we insert 2 empty tokens (domain and hash) so that the |
| 92 | // rest of the library references known fields at a constant location. |
| 93 | if tokensLen == v1TokenCounts { |
| 94 | // Extend the array (we know the backend is big enough) |
| 95 | tokens = append(tokens[:AckDomainTokenPos+2], tokens[AckDomainTokenPos:]...) |
| 96 | // Clear the domain and hash tokens |
| 97 | tokens[AckDomainTokenPos], tokens[AckAccHashTokenPos] = "", "" |
| 98 | |
| 99 | } else if tokens[AckDomainTokenPos] == "_" { |
| 100 | // If domain is "_", replace with empty value. |
| 101 | tokens[AckDomainTokenPos] = "" |
| 102 | } |
| 103 | return tokens, nil |
| 104 | } |