Module: Ticketing::Protocol

Defined in:
lib/ticketing/protocol.rb

Overview

Wire protocol — byte-compatible with ticketing-server/docs/protocal_client.md. 와이어 프로토콜 — 서버 문서 protocal_client.md와 바이트 호환.

Defined Under Namespace

Classes: FrameParser

Constant Summary collapse

MAX_KEY_LEN =
128
MAX_LINE_LEN =
192
MAX_HANDSHAKE_LINE =
256
OP_ACQUIRE =
"A".ord
OP_RELEASE =
"R".ord
NL =
"\n".ord

Class Method Summary collapse

Class Method Details

.acquire_frame(key, wait_secs, lease_secs) ⇒ Object

A[wait:u16][lease:u16]key\n — seconds rounded up, lease ≥ 1s. 초 올림, lease 최소 1초.



32
33
34
# File 'lib/ticketing/protocol.rb', line 32

def acquire_frame(key, wait_secs, lease_secs)
  [OP_ACQUIRE, ceil_secs_u16(wait_secs, 0), ceil_secs_u16(lease_secs, 1)].pack("CS>S>") + key.b + "\n".b
end

.auth_digest(token, nonce) ⇒ Object

base64url(SHA-256(token ∥ nonce)). 인증 응답 다이제스트.



20
21
22
# File 'lib/ticketing/protocol.rb', line 20

def auth_digest(token, nonce)
  [Digest::SHA256.digest(token.b + nonce)].pack("m0").tr("+/", "-_").delete("=")
end

.ceil_secs_u16(secs, min) ⇒ Object



39
# File 'lib/ticketing/protocol.rb', line 39

def ceil_secs_u16(secs, min) = secs.ceil.clamp(min, 0xFFFF)

.parse_reply(frame) ⇒ Object

A parsed server reply: [op, text, token]. 파싱된 서버 응답.



42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ticketing/protocol.rb', line 42

def parse_reply(frame)
  return nil if frame.empty?

  op = frame[0]
  case op
  when "A"
    return nil if frame.bytesize < 9

    [op, frame.byteslice(9..).force_encoding(Encoding::UTF_8), frame.byteslice(1, 8).unpack1("Q>")]
  when "T", "R", "N", "M", "E"
    [op, frame.byteslice(1..).force_encoding(Encoding::UTF_8), 0]
  end
end

.release_frame(key) ⇒ Object

Rkey\n



37
# File 'lib/ticketing/protocol.rb', line 37

def release_frame(key) = "R".b + key.b + "\n".b

.validate_key!(key) ⇒ Object

Key: 1..=128 UTF-8 bytes, no space/newline. 키 규칙 검증.

Raises:



25
26
27
28
29
# File 'lib/ticketing/protocol.rb', line 25

def validate_key!(key)
  bytes = key.bytesize
  raise TicketError.new(:invalid_input, "key must be 1..=128 bytes") if bytes.zero? || bytes > MAX_KEY_LEN
  raise TicketError.new(:invalid_input, "key must not contain spaces or newlines") if key.match?(/[ \n\r]/)
end