jetstream-api 0.24.0__tar.gz → 0.25.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jetstream_api-0.24.0/jetstream_api.egg-info → jetstream_api-0.25.0}/PKG-INFO +20 -1
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/README.md +19 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/__init__.py +1 -1
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/admin.py +81 -5
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/properties.py +143 -23
- {jetstream_api-0.24.0 → jetstream_api-0.25.0/jetstream_api.egg-info}/PKG-INFO +20 -1
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/pyproject.toml +1 -1
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/LICENSE.txt +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/_codec.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/_consumer.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/_groupwire.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/_propv2.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/_qleader.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/_throttle.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/admintopic.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/common.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/connectivity.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/exception.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/msg.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/partitioner.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/pattern.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/producer.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/py.typed +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/qmgr.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/topic.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/ilink/util.py +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/jetstream_api.egg-info/SOURCES.txt +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/jetstream_api.egg-info/dependency_links.txt +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/jetstream_api.egg-info/requires.txt +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/jetstream_api.egg-info/top_level.txt +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/setup.cfg +0 -0
- {jetstream_api-0.24.0 → jetstream_api-0.25.0}/tests/test_example.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jetstream-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: Python client API for iLink M.O.M. (Message Oriented Middleware)
|
|
5
5
|
Author: snowjeans
|
|
6
6
|
License: Boost Software License - Version 1.0 - August 17th, 2003
|
|
@@ -60,6 +60,25 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
|
|
|
60
60
|
## 설치 방법
|
|
61
61
|
pip install jetstream-api
|
|
62
62
|
|
|
63
|
+
## 0.25.0 변경 - 서비스 속성 · 로거 Property v2(JSON) · 블롭 왕복 보존 (자바 v2.21.0 와 같음, 짝 엔진 7.0.1.3624 이상)
|
|
64
|
+
|
|
65
|
+
- **서비스 속성이 엔진 7 과 JSON 으로 오간다**(엔진 P5-2). ``ILAdminService.getProperty`` 는 SERVICE GET + LOGGER LIST(시스템 ·
|
|
66
|
+
클라이언트 로그 칸), ``setProperty`` 는 **바꾼 칸만** SERVICE ALTER + 바뀐 로그 카테고리마다 LOGGER ALTER 다. 6.x 엔진은 기존 블롭.
|
|
67
|
+
☠ **7.0.1.3623 이하 7.x 엔진에는 서비스 속성 조회 · 변경이 거절된다.**
|
|
68
|
+
- 더함: ``ILAdminService.setPropertyWithResult`` (``ILPropertyResult``, 로그 키는 ``LOGGER.SYS.LEVEL`` 모양, ``IP`` 는 ``RESTART`` -
|
|
69
|
+
재기동 뒤 반영, 나머지는 ``NOW``). 요청이 둘 이상이라 **원자적이지 않다** - 로거 변경이 거절되면 사유 뒤에
|
|
70
|
+
``[LOGGER <카테고리> 거절 - 이미 적용: SERVICE, ...]`` 가 붙는다(이미 적용된 쪽은 되돌리지 않는다).
|
|
71
|
+
- **서비스 · 큐관리자 속성 블롭 왕복 보존**: 읽은 객체를 그대로 ``setProperty`` 로 되보내면 엔진이 준 바이트가 그대로 나간다.
|
|
72
|
+
전에는 클라가 모르는 자리(하위호환 로그 칸 · 스레드 풀 칸 등)를 0 이나 기본값으로 덮었다.
|
|
73
|
+
- 문자열 상한을 엔진과 맞췄다: 큐 설명(``description``) **199바이트**(0.23.0 은 200), 서비스 IP 99 · 이름 47 · 허브 IP 23 · HOMEPATH 99
|
|
74
|
+
(엔진 7.0.1.3623 이상과 같다). 옛 판에서 저장된 더 긴 값은 읽기 · 되보내기에서 거절되지 않는다(읽을 때는 상한을 묻지 않는다).
|
|
75
|
+
- 서비스 ``aclType`` · ``relayType`` 은 0/1 만 받는다(그 밖은 엔진 7.0.1.3619 이상이 거절, 엔진 7 JSON 경로는 클라가 먼저 거절).
|
|
76
|
+
- 채널: 종류 · 방향을 바꿔 ``setChannelProperty`` 를 부르면 엔진 7 은 ``MIMQE_IMMUTABLE_PROPERTY (TYPE fixed at <현재 값>)`` 로 거절하고,
|
|
77
|
+
6.x 블롭은 조용히 옛 값을 유지한다(문서 정정 - 옛 문구 "다르면 NOT_FOUND" 는 틀렸다). TLS 채널을 JSON 으로 만들거나 바꾸는 것은 엔진
|
|
78
|
+
7.0.1.3617 이상에서 맞다(그 전 판은 기본 인증서를 채우지 않아 ``MIMQE_SSL_ERROR``).
|
|
79
|
+
- 세션: 엔진 7.0.1.3617 이상에서 ``destroyedTime`` 이 ``-1`` 이 아니면 끊긴 세션(보관 중)이다 - 상태는 ``EXCEPTION`` 일 수 있다.
|
|
80
|
+
그 전 판은 끊긴 세션도 ``-1`` 이라 가릴 수 없다.
|
|
81
|
+
|
|
63
82
|
## 0.24.0 변경 - 채널 · 세션 Property v2(JSON) · IBMMQ 채널 종류 (자바 v2.20.0 와 같음, 짝 엔진 7.0.1.3615 이상)
|
|
64
83
|
|
|
65
84
|
- **채널 관리가 엔진 7 과 JSON(Property v2) 으로 오간다**(엔진 P4). 함수 이름은 그대로 - ``createChannel`` · ``setChannelProperty`` ·
|
|
@@ -10,6 +10,25 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
|
|
|
10
10
|
## 설치 방법
|
|
11
11
|
pip install jetstream-api
|
|
12
12
|
|
|
13
|
+
## 0.25.0 변경 - 서비스 속성 · 로거 Property v2(JSON) · 블롭 왕복 보존 (자바 v2.21.0 와 같음, 짝 엔진 7.0.1.3624 이상)
|
|
14
|
+
|
|
15
|
+
- **서비스 속성이 엔진 7 과 JSON 으로 오간다**(엔진 P5-2). ``ILAdminService.getProperty`` 는 SERVICE GET + LOGGER LIST(시스템 ·
|
|
16
|
+
클라이언트 로그 칸), ``setProperty`` 는 **바꾼 칸만** SERVICE ALTER + 바뀐 로그 카테고리마다 LOGGER ALTER 다. 6.x 엔진은 기존 블롭.
|
|
17
|
+
☠ **7.0.1.3623 이하 7.x 엔진에는 서비스 속성 조회 · 변경이 거절된다.**
|
|
18
|
+
- 더함: ``ILAdminService.setPropertyWithResult`` (``ILPropertyResult``, 로그 키는 ``LOGGER.SYS.LEVEL`` 모양, ``IP`` 는 ``RESTART`` -
|
|
19
|
+
재기동 뒤 반영, 나머지는 ``NOW``). 요청이 둘 이상이라 **원자적이지 않다** - 로거 변경이 거절되면 사유 뒤에
|
|
20
|
+
``[LOGGER <카테고리> 거절 - 이미 적용: SERVICE, ...]`` 가 붙는다(이미 적용된 쪽은 되돌리지 않는다).
|
|
21
|
+
- **서비스 · 큐관리자 속성 블롭 왕복 보존**: 읽은 객체를 그대로 ``setProperty`` 로 되보내면 엔진이 준 바이트가 그대로 나간다.
|
|
22
|
+
전에는 클라가 모르는 자리(하위호환 로그 칸 · 스레드 풀 칸 등)를 0 이나 기본값으로 덮었다.
|
|
23
|
+
- 문자열 상한을 엔진과 맞췄다: 큐 설명(``description``) **199바이트**(0.23.0 은 200), 서비스 IP 99 · 이름 47 · 허브 IP 23 · HOMEPATH 99
|
|
24
|
+
(엔진 7.0.1.3623 이상과 같다). 옛 판에서 저장된 더 긴 값은 읽기 · 되보내기에서 거절되지 않는다(읽을 때는 상한을 묻지 않는다).
|
|
25
|
+
- 서비스 ``aclType`` · ``relayType`` 은 0/1 만 받는다(그 밖은 엔진 7.0.1.3619 이상이 거절, 엔진 7 JSON 경로는 클라가 먼저 거절).
|
|
26
|
+
- 채널: 종류 · 방향을 바꿔 ``setChannelProperty`` 를 부르면 엔진 7 은 ``MIMQE_IMMUTABLE_PROPERTY (TYPE fixed at <현재 값>)`` 로 거절하고,
|
|
27
|
+
6.x 블롭은 조용히 옛 값을 유지한다(문서 정정 - 옛 문구 "다르면 NOT_FOUND" 는 틀렸다). TLS 채널을 JSON 으로 만들거나 바꾸는 것은 엔진
|
|
28
|
+
7.0.1.3617 이상에서 맞다(그 전 판은 기본 인증서를 채우지 않아 ``MIMQE_SSL_ERROR``).
|
|
29
|
+
- 세션: 엔진 7.0.1.3617 이상에서 ``destroyedTime`` 이 ``-1`` 이 아니면 끊긴 세션(보관 중)이다 - 상태는 ``EXCEPTION`` 일 수 있다.
|
|
30
|
+
그 전 판은 끊긴 세션도 ``-1`` 이라 가릴 수 없다.
|
|
31
|
+
|
|
13
32
|
## 0.24.0 변경 - 채널 · 세션 Property v2(JSON) · IBMMQ 채널 종류 (자바 v2.20.0 와 같음, 짝 엔진 7.0.1.3615 이상)
|
|
14
33
|
|
|
15
34
|
- **채널 관리가 엔진 7 과 JSON(Property v2) 으로 오간다**(엔진 P4). 함수 이름은 그대로 - ``createChannel`` · ``setChannelProperty`` ·
|
|
@@ -100,6 +100,46 @@ def _session_get_v2(service, qmgrName: str, sessionId: str) -> ILSessionProperty
|
|
|
100
100
|
return ILSessionProperty()._pv2_from_body(_propv2.request(service, qmgrName, _propv2.PROP_GET, {"_TYPE": "SESSION", "ID": sessionId}))
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
# ── 다음 판 Property v2 SERVICE + LOGGER(엔진 P5-2) ── 서비스 레벨(큐관리자 이름 빈칸)
|
|
104
|
+
|
|
105
|
+
def _service_get_v2(service) -> ILServiceProperty:
|
|
106
|
+
prop = ILServiceProperty()._pv2_from_body(_propv2.request(service, "", _propv2.PROP_GET, {"_TYPE": "SERVICE"}))
|
|
107
|
+
items = _propv2.request(service, "", _propv2.PROP_LIST, {"_TYPE": "LOGGER"}).get("_ITEMS", []) or []
|
|
108
|
+
if not isinstance(items, list):
|
|
109
|
+
raise _propv2.PropV2Error("_ITEMS must be ARRAY of OBJ")
|
|
110
|
+
return prop._pv2_logger_fill(items)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _service_set_v2(service, prop: ILServiceProperty) -> ILPropertyResult:
|
|
114
|
+
# SERVICE ALTER(바뀐 칸) 뒤 바뀐 카테고리마다 LOGGER ALTER. 원자성은 없다 - 실패하면 이미 적용된 쪽을 사유에 붙인다(엔진 합의)
|
|
115
|
+
merged = {"_APPLIED": [], "_IGNORED": [], "_NORMALIZED": []}
|
|
116
|
+
done = []
|
|
117
|
+
|
|
118
|
+
def merge(r: dict, prefix: str) -> None:
|
|
119
|
+
for k in merged:
|
|
120
|
+
for e in r.get(k, []) or []:
|
|
121
|
+
if isinstance(e, dict):
|
|
122
|
+
merged[k].append(dict(e, KEY=prefix + str(e.get("KEY", ""))))
|
|
123
|
+
|
|
124
|
+
body = prop._pv2_patch_body()
|
|
125
|
+
if body:
|
|
126
|
+
merge(_propv2.request(service, "", _propv2.PROP_ALTER, dict({"_TYPE": "SERVICE"}, **body)), "")
|
|
127
|
+
prop._pv2_clear()
|
|
128
|
+
done.append("SERVICE")
|
|
129
|
+
for lb in prop._pv2_logger_patches():
|
|
130
|
+
cat = lb["CATEGORY"]
|
|
131
|
+
try:
|
|
132
|
+
r = _propv2.request(service, "", _propv2.PROP_ALTER, lb)
|
|
133
|
+
except ILOperationException as exc:
|
|
134
|
+
raise ILOperationException("%s [LOGGER %s 거절%s]" % (exc, cat, (" - 이미 적용: " + ", ".join(done)) if done else ""), exc) from exc
|
|
135
|
+
merge(r, "LOGGER.%s." % cat)
|
|
136
|
+
snap = dict(prop.__dict__.get("_il_log_snap") or ILServiceProperty()._pv2_log_now())
|
|
137
|
+
snap[cat] = prop._pv2_log_now()[cat]
|
|
138
|
+
object.__setattr__(prop, "_il_log_snap", snap)
|
|
139
|
+
done.append("LOGGER " + cat)
|
|
140
|
+
return ILPropertyResult(merged)
|
|
141
|
+
|
|
142
|
+
|
|
103
143
|
class ILAdminService:
|
|
104
144
|
"""ilink 서버를 **관리**하는 클라이언트. 큐 관리자 생성/기동/속성 변경을 맡는다.
|
|
105
145
|
|
|
@@ -381,12 +421,16 @@ class ILAdminService:
|
|
|
381
421
|
**읽은 뒤 고쳐서 :meth:`setProperty` 로 되돌려주는 방식**이다.
|
|
382
422
|
빈 객체를 새로 만들어 넣으면 지정하지 않은 항목이 기본값으로 덮인다.
|
|
383
423
|
|
|
424
|
+
엔진 7 이면 JSON 으로 받는다(다음 판) - 서비스 칸은 SERVICE GET, 로그 칸(시스템 · 클라이언트)은 LOGGER LIST 다.
|
|
425
|
+
|
|
384
426
|
Example::
|
|
385
427
|
|
|
386
428
|
prop = svc.getProperty()
|
|
387
429
|
print(prop.isTraceEnabled())
|
|
388
430
|
"""
|
|
389
431
|
try:
|
|
432
|
+
if _propv2.peer_speaks_v2(self.version): # 다음 판(엔진 P5-2): 7 이면 SERVICE GET + LOGGER LIST(JSON), 6.x 면 아래 블롭
|
|
433
|
+
return _service_get_v2(self.service)
|
|
390
434
|
res_msg = self.service.inquire(ILC.MIMQ_GET_SERVER_PROPERTY)
|
|
391
435
|
return ILServiceProperty(res_msg.getDataMsg().getData())
|
|
392
436
|
except _PASSTHROUGH_EXCEPTIONS:
|
|
@@ -398,7 +442,8 @@ class ILAdminService:
|
|
|
398
442
|
"""서버 전체(ilsvc) 속성을 변경한다.
|
|
399
443
|
|
|
400
444
|
Args:
|
|
401
|
-
vo (ILServiceProperty): 반영할 설정. **전체가 통째로 덮어써진다.**
|
|
445
|
+
vo (ILServiceProperty): 반영할 설정. 6.x 엔진에는 **전체가 통째로 덮어써진다.** 엔진 7 에는 바꾼 칸만 간다(다음 판,
|
|
446
|
+
:meth:`setPropertyWithResult` 참고 - 요청이 둘 이상이라 원자적이지 않다).
|
|
402
447
|
|
|
403
448
|
Raises:
|
|
404
449
|
ILOperationException: 서버가 변경을 거절했을 때.
|
|
@@ -415,6 +460,9 @@ class ILAdminService:
|
|
|
415
460
|
svc.setProperty(prop)
|
|
416
461
|
"""
|
|
417
462
|
try:
|
|
463
|
+
if _propv2.peer_speaks_v2(self.version): # 다음 판(엔진 P5-2): 7 이면 바꾼 칸만 JSON, 6.x 면 아래 블롭(전체)
|
|
464
|
+
self.setPropertyWithResult(vo)
|
|
465
|
+
return
|
|
418
466
|
self.service.apply(
|
|
419
467
|
ILC.MIMQ_SET_SERVER_PROPERTY,
|
|
420
468
|
vo.get_serialized(),
|
|
@@ -425,6 +473,34 @@ class ILAdminService:
|
|
|
425
473
|
except Exception as exc:
|
|
426
474
|
raise ILException(exc) from exc
|
|
427
475
|
|
|
476
|
+
def setPropertyWithResult(self, vo: ILServiceProperty) -> ILPropertyResult:
|
|
477
|
+
""":meth:`setProperty` 와 같고, 엔진이 무엇을 적용 · 무시했는지 돌려준다(다음 판).
|
|
478
|
+
|
|
479
|
+
엔진 7 에는 **바꾼 칸만** 보낸다 - 서비스 칸은 SERVICE ALTER, 로그 칸(시스템 · 클라이언트)은 바뀐 카테고리마다 LOGGER ALTER 다.
|
|
480
|
+
결과의 로그 키는 ``LOGGER.SYS.LEVEL`` 모양이다. ``IP`` 는 ``"RESTART"`` (재기동 뒤 반영, :meth:`ILPropertyResult.needs_restart`),
|
|
481
|
+
나머지는 ``"NOW"`` 다. 바꾼 것이 없으면 보내지 않고 빈 결과를 돌려준다.
|
|
482
|
+
|
|
483
|
+
Args:
|
|
484
|
+
vo (ILServiceProperty): 바꿀 설정. :meth:`getProperty` 로 읽어 고친 객체를 넘긴다.
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
ILPropertyResult: 적용 · 무시 목록. **6.x 엔진이면 빈 결과**다(블롭으로 전체를 보낸다).
|
|
488
|
+
|
|
489
|
+
Raises:
|
|
490
|
+
ILOperationException: 엔진이 거절했을 때(사유 그대로). 요청이 둘 이상이라 **원자적이지 않다** - 로거 변경이 거절되면
|
|
491
|
+
사유 뒤에 ``[LOGGER <카테고리> 거절 - 이미 적용: SERVICE, ...]`` 를 붙인다(이미 적용된 쪽은 되돌리지 않는다).
|
|
492
|
+
ILException: 통신 실패.
|
|
493
|
+
"""
|
|
494
|
+
try:
|
|
495
|
+
if not _propv2.peer_speaks_v2(self.version):
|
|
496
|
+
self.setProperty(vo)
|
|
497
|
+
return ILPropertyResult()
|
|
498
|
+
return _service_set_v2(self.service, vo)
|
|
499
|
+
except _PASSTHROUGH_EXCEPTIONS:
|
|
500
|
+
raise
|
|
501
|
+
except Exception as exc:
|
|
502
|
+
raise ILException(exc) from exc
|
|
503
|
+
|
|
428
504
|
def setSystemTrace(self, enabled: bool) -> None:
|
|
429
505
|
"""서버 시스템 트레이스를 켜거나 끈다.
|
|
430
506
|
|
|
@@ -5909,10 +5985,10 @@ class ILAdminQmgr:
|
|
|
5909
5985
|
전체가 통째로 덮어써진다.
|
|
5910
5986
|
|
|
5911
5987
|
Warning:
|
|
5912
|
-
**종류(type)와 방향(direction)은 바꿀 수
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5988
|
+
**종류(type)와 방향(direction)은 바꿀 수 없다** - 바꾸려면 지우고 다시 만들어야 한다(이 메서드는 제거 · 재생성을 하지 않는다).
|
|
5989
|
+
엔진 7(JSON)은 바꿔 보내면 ``MIMQE_IMMUTABLE_PROPERTY (TYPE fixed at <현재 값>)`` 로 **거절**한다(같은 값이면 통과).
|
|
5990
|
+
☠ 6.x 블롭 경로는 거절하지 않고 **조용히 옛 값을 유지한다**(성공을 돌려준다, 엔진 6.3.4 동작).
|
|
5991
|
+
``MIMQE_OBJECT_NOT_FOUND`` 는 채널 이름이 없을 때다.
|
|
5916
5992
|
|
|
5917
5993
|
Note:
|
|
5918
5994
|
**클러스터 팔로워에서는 거부된다.** 구성 변경(생성/변경/삭제)은 리더에서만
|
|
@@ -40,6 +40,19 @@ def _format_millis(value: int, fmt: str) -> str:
|
|
|
40
40
|
LEGACY_FORCE_RELOAD_MIN = 1048576
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
def _patch_blob(raw: bytes, ref: bytes, built: bytes, fields) -> bytes:
|
|
44
|
+
"""서버 원본 ``raw`` 위에, 클라 표현이 달라진 칸만 ``built`` 에서 옮긴다(왕복 보존, 다음 판).
|
|
45
|
+
|
|
46
|
+
``ref`` 는 원본을 읽은 직후 클라가 짠 바이트다. 칸 ``(오프셋, 폭)`` 마다 ``built`` 와 ``ref`` 가 다르면(= 그 뒤 바꿨으면)
|
|
47
|
+
그 칸을 덮고, 같으면 원본 바이트를 둔다. 표에 없는 자리(클라가 모르는 칸 · 예약)는 늘 원본 그대로다.
|
|
48
|
+
"""
|
|
49
|
+
out = bytearray(raw)
|
|
50
|
+
for off, w in fields:
|
|
51
|
+
if built[off:off + w] != ref[off:off + w]:
|
|
52
|
+
out[off:off + w] = built[off:off + w]
|
|
53
|
+
return bytes(out)
|
|
54
|
+
|
|
55
|
+
|
|
43
56
|
def _has_value(raw) -> bool:
|
|
44
57
|
"""서버가 준 원본이 쓸 만한지 본다.
|
|
45
58
|
|
|
@@ -753,7 +766,7 @@ class ILQueueProperty(_AutoAccessor):
|
|
|
753
766
|
스펙: 기본 LOCAL · 범위 LOCAL | REMOTE | XMIT · 변경 불가.
|
|
754
767
|
description (str): 큐 설명(다음 판, 엔진 7). 기본 ``""``. **생성할 때만** 지정한다 - 변경(ALTER)으로 보내면 엔진이 거절한다.
|
|
755
768
|
☠ **엔진 7(JSON)에서만 오간다** - 6.x 엔진과의 고정폭 블롭에는 싣지 않는다.
|
|
756
|
-
스펙: 기본 "" · 범위
|
|
769
|
+
스펙: 기본 "" · 범위 199바이트 이하 문자열(칸 폭 200 − 1, 엔진 7.0.1.3620 571 과 같다) · 생성 전용.
|
|
757
770
|
depth (int): **읽기 전용** 현재 깊이. 기본 0.
|
|
758
771
|
스펙: 기본 0 · 범위 0~2147483647 · 단위 건 · 변경 불가.
|
|
759
772
|
maxDepth (int): 최대 깊이. 넘으면 put 이 거부된다. 기본 99999999.
|
|
@@ -832,7 +845,7 @@ class ILQueueProperty(_AutoAccessor):
|
|
|
832
845
|
# 엔진 QueueProperty::Validate() 와 같은 규칙.
|
|
833
846
|
_SPEC = {
|
|
834
847
|
"name": _spec_maxlen(47),
|
|
835
|
-
"description": _spec_maxlen(
|
|
848
|
+
"description": _spec_maxlen(199),
|
|
836
849
|
"triggerProcess": _spec_maxlen(999),
|
|
837
850
|
"remoteQmgrName": _spec_maxlen(47),
|
|
838
851
|
"remoteQueueName": _spec_maxlen(47),
|
|
@@ -3389,9 +3402,22 @@ class ILQmgrProperty(_AutoAccessor):
|
|
|
3389
3402
|
if len(ba) > offset and ba[offset] != 0x00:
|
|
3390
3403
|
self.subGroupTimeoutSec = ba_pick_int(ba, offset, 4)
|
|
3391
3404
|
offset += 4
|
|
3405
|
+
# 왕복 보존(다음 판): 원본과, 원본을 클라가 다시 짠 바이트
|
|
3406
|
+
# ☠ 조회 경로를 실패시키지 않는다 - 다시 짜기가 실패하면(폭 검사 등) 원본 보관을 포기하고 옛 직렬화로 간다
|
|
3407
|
+
try:
|
|
3408
|
+
self._blobBuilt = self._build_blob()
|
|
3409
|
+
self._blobRaw = bytes(ba[:ILC.MIMQ_VO_QMGR_LEN])
|
|
3410
|
+
except Exception: # noqa: BLE001
|
|
3411
|
+
self._blobRaw = None
|
|
3392
3412
|
except Exception as exc:
|
|
3393
3413
|
raise ILException(exc) from exc
|
|
3394
3414
|
|
|
3415
|
+
#: 클라가 아는 칸 ``(오프셋, 폭)``. 이 밖의 자리(SSL 포트 272 · 하위호환 로그 278 · 321 · 344 · 396 · 풀 446 · 세션 610)는 원본 그대로 간다.
|
|
3416
|
+
_BLOB_FIELDS = ((0, 6), (6, 60), (66, 100), (166, 100), (266, 6), (301, 20), (322, 20), (342, 2), (346, 10), (356, 10), (366, 20),
|
|
3417
|
+
(386, 10), (406, 10), (416, 10), (426, 10), (436, 10), (466, 10), (476, 20), (496, 2), (498, 13), (511, 5),
|
|
3418
|
+
(516, 2), (518, 15), (533, 5), (538, 2), (540, 15), (555, 5), (560, 2), (562, 15), (577, 5), (582, 2), (584, 15),
|
|
3419
|
+
(599, 5), (604, 2), (606, 2), (608, 2), (620, 32), (652, 10), (662, 4))
|
|
3420
|
+
|
|
3395
3421
|
def get_serialized(self, with_topic_logger: bool = True) -> bytes:
|
|
3396
3422
|
"""이 객체를 서버 규격의 **고정폭 바이트**로 직렬화한다.
|
|
3397
3423
|
|
|
@@ -3401,7 +3427,32 @@ class ILQmgrProperty(_AutoAccessor):
|
|
|
3401
3427
|
Note:
|
|
3402
3428
|
라이브러리가 요청을 보낼 때 내부적으로 부른다. 응용이 직접 부를
|
|
3403
3429
|
일은 거의 없다.
|
|
3430
|
+
|
|
3431
|
+
**서버가 준 바이트로 만든 객체는 그 원본 위에 바뀐 칸만 덮는다** - 읽은 객체를 그대로 되보내면 같은 바이트가 나간다
|
|
3432
|
+
(다음 판). 클라가 모르는 자리(하위호환 로그 · 스레드 풀 · 세션 칸 등)를 0 이나 기본값으로 덮지 않는다.
|
|
3404
3433
|
"""
|
|
3434
|
+
built = self._build_blob()
|
|
3435
|
+
raw = self.__dict__.get("_blobRaw")
|
|
3436
|
+
ba = bytearray(built if raw is None else _patch_blob(raw, self._blobBuilt, built, type(self)._BLOB_FIELDS))
|
|
3437
|
+
topic_offset, session_offset = 496, 610
|
|
3438
|
+
if not with_topic_logger:
|
|
3439
|
+
for i in range(20):
|
|
3440
|
+
ba[topic_offset + i] = 0
|
|
3441
|
+
raw = getattr(self, "_volumeTailRaw", None)
|
|
3442
|
+
if raw:
|
|
3443
|
+
ba[topic_offset:topic_offset + 20] = raw
|
|
3444
|
+
else:
|
|
3445
|
+
ba_merge(max(self.volumeMonitorSizeLimit, LEGACY_FORCE_RELOAD_MIN),
|
|
3446
|
+
ba, topic_offset, 20)
|
|
3447
|
+
raw2 = getattr(self, "_sessionPerThreadRaw", None)
|
|
3448
|
+
if raw2:
|
|
3449
|
+
ba[session_offset:session_offset + 10] = raw2
|
|
3450
|
+
else:
|
|
3451
|
+
ba_merge(LEGACY_SESSION_PER_THREAD, ba, session_offset, 10)
|
|
3452
|
+
return bytes(ba)
|
|
3453
|
+
|
|
3454
|
+
def _build_blob(self) -> bytes:
|
|
3455
|
+
# 필드만으로 짠 바이트(원본 없음 기준). 서버 원본이 있으면 get_serialized 가 원본 위에 바뀐 칸만 옮긴다
|
|
3405
3456
|
ba = bytearray(ILC.MIMQ_VO_QMGR_LEN)
|
|
3406
3457
|
offset = 0
|
|
3407
3458
|
ba_merge(self.status, ba, offset, 6)
|
|
@@ -3461,7 +3512,6 @@ class ILQmgrProperty(_AutoAccessor):
|
|
|
3461
3512
|
# 이 자리는 구엔진의 volumeMonitorForceReloadSize 다. 값을 실어 보내면
|
|
3462
3513
|
# 구엔진이 자기 필드로 읽어 imqlsr 가 SIGFPE 로 죽는다(6.3.1.2813 실측).
|
|
3463
3514
|
# 비워 보내려면 get_serialized(with_topic_logger=False) 를 쓴다.
|
|
3464
|
-
topic_offset = offset
|
|
3465
3515
|
ba_merge(self.logLevelTopic, ba, offset, 2)
|
|
3466
3516
|
offset += 2
|
|
3467
3517
|
ba_merge(self.logFileSizeTopic, ba, offset, 13)
|
|
@@ -3499,7 +3549,6 @@ class ILQmgrProperty(_AutoAccessor):
|
|
|
3499
3549
|
ba_merge(self.aclType, ba, offset, 2)
|
|
3500
3550
|
offset += 2
|
|
3501
3551
|
# 구엔진에만 있는 sessionPerThread 자리 - 0 을 보내면 큐관리자가 죽는다
|
|
3502
|
-
session_offset = offset
|
|
3503
3552
|
offset += 10
|
|
3504
3553
|
ba_merge(self.deadLetterQueueName, ba, offset, 32)
|
|
3505
3554
|
offset += 32
|
|
@@ -3507,25 +3556,6 @@ class ILQmgrProperty(_AutoAccessor):
|
|
|
3507
3556
|
offset += 10
|
|
3508
3557
|
ba_merge(self.subGroupTimeoutSec, ba, offset, 4)
|
|
3509
3558
|
offset += 4
|
|
3510
|
-
if not with_topic_logger:
|
|
3511
|
-
for i in range(20):
|
|
3512
|
-
ba[topic_offset + i] = 0
|
|
3513
|
-
raw = getattr(self, "_volumeTailRaw", None)
|
|
3514
|
-
if raw:
|
|
3515
|
-
# 서버가 준 값을 그대로 되돌려 준다
|
|
3516
|
-
ba[topic_offset:topic_offset + 20] = raw
|
|
3517
|
-
else:
|
|
3518
|
-
# 받은 값이 없다 - 엔진 생성자와 같이 sizeLimit 을 따라간다
|
|
3519
|
-
# (6.3 ManagerProperty.hpp:143 이 mForceReloadSize = mSizeLimit).
|
|
3520
|
-
# 엔진 세터가 1048576 미만을 올려 잡으므로 그 아래로 내리지 않는다.
|
|
3521
|
-
ba_merge(max(self.volumeMonitorSizeLimit, LEGACY_FORCE_RELOAD_MIN),
|
|
3522
|
-
ba, topic_offset, 20)
|
|
3523
|
-
# 구엔진에만 있는 sessionPerThread 도 되돌려 준다
|
|
3524
|
-
raw2 = getattr(self, "_sessionPerThreadRaw", None)
|
|
3525
|
-
if raw2:
|
|
3526
|
-
ba[session_offset:session_offset + 10] = raw2
|
|
3527
|
-
else:
|
|
3528
|
-
ba_merge(LEGACY_SESSION_PER_THREAD, ba, session_offset, 10)
|
|
3529
3559
|
return bytes(ba)
|
|
3530
3560
|
|
|
3531
3561
|
def get_status_string(self) -> str:
|
|
@@ -4440,6 +4470,76 @@ class ILServiceProperty(_AutoAccessor):
|
|
|
4440
4470
|
out[key] = back[getattr(self, field)]
|
|
4441
4471
|
return {k: out[k] for _, (k, _) in cls._PV2_KEYS.items() if k in out} # 표 순서
|
|
4442
4472
|
|
|
4473
|
+
#: 다음 판 Property v2 LOGGER(엔진 P5-2): 서비스 로거 카테고리 -> (레벨 · 회전 크기 · 보관 개수 필드). 서비스는 SYS · CLI 만.
|
|
4474
|
+
_PV2_LOGGERS = {"SYS": ("logLevelSystem", "logFileSizeSystem", "logFileCountSystem"),
|
|
4475
|
+
"CLI": ("logLevelClient", "logFileSizeClient", "logFileCountClient")}
|
|
4476
|
+
#: LEVEL 와이어 글자(코드 0~7 순서, :meth:`ILC.get_log_level_string` 과 같다 - 4 는 ``"WARNING"``). ``"WARN"`` 은 옛 XML 별칭으로 받기만 한다.
|
|
4477
|
+
_PV2_LOG_LEVELS = ("TRACE", "DEBUG", "MSG", "INFO", "WARNING", "ERROR", "FATAL", "SYSTEM")
|
|
4478
|
+
|
|
4479
|
+
def _pv2_log_now(self) -> dict:
|
|
4480
|
+
# 카테고리 -> (레벨, 크기, 개수) 지금 값
|
|
4481
|
+
return {c: tuple(getattr(self, f) for f in fs) for c, fs in type(self)._PV2_LOGGERS.items()}
|
|
4482
|
+
|
|
4483
|
+
def _pv2_logger_fill(self, items: list) -> "ILServiceProperty":
|
|
4484
|
+
"""LOGGER LIST 원소(JSON)로 로그 칸을 채운다. **라이브러리 내부용이다.** 서비스가 모르는 카테고리는 버린다.
|
|
4485
|
+
|
|
4486
|
+
채운 값을 비교 기준으로 둔다 - :meth:`_pv2_logger_patches` 는 이 기준과 달라진 칸만 싣는다.
|
|
4487
|
+
|
|
4488
|
+
Raises:
|
|
4489
|
+
PropV2Error: 값 종류가 다르거나 LEVEL 글자를 모를 때(조용히 오독하지 않는다).
|
|
4490
|
+
"""
|
|
4491
|
+
from . import _propv2
|
|
4492
|
+
cls = type(self)
|
|
4493
|
+
for e in items:
|
|
4494
|
+
if not isinstance(e, dict):
|
|
4495
|
+
raise _propv2.PropV2Error("_ITEMS must be ARRAY of OBJ")
|
|
4496
|
+
fs = cls._PV2_LOGGERS.get(_propv2.take(e, "CATEGORY", "STR"))
|
|
4497
|
+
if fs is None:
|
|
4498
|
+
continue
|
|
4499
|
+
lv = _propv2.take(e, "LEVEL", "STR")
|
|
4500
|
+
if lv is not None:
|
|
4501
|
+
k = "WARNING" if lv == "WARN" else lv
|
|
4502
|
+
if k not in cls._PV2_LOG_LEVELS:
|
|
4503
|
+
raise _propv2.PropV2Error("LEVEL: unknown value %r" % (lv,))
|
|
4504
|
+
object.__setattr__(self, fs[0], cls._PV2_LOG_LEVELS.index(k))
|
|
4505
|
+
for f, key in ((fs[1], "FILESIZE"), (fs[2], "FILECOUNT")):
|
|
4506
|
+
v = _propv2.take(e, key, "INT")
|
|
4507
|
+
if v is not None:
|
|
4508
|
+
object.__setattr__(self, f, v)
|
|
4509
|
+
self._pv2_logger_sent()
|
|
4510
|
+
return self
|
|
4511
|
+
|
|
4512
|
+
def _pv2_logger_patches(self) -> list:
|
|
4513
|
+
"""바뀐 카테고리마다 LOGGER ALTER 본문(``_TYPE`` · ``CATEGORY`` + 바뀐 키만)을 만든다. **라이브러리 내부용이다.**
|
|
4514
|
+
|
|
4515
|
+
기준은 마지막으로 읽은(또는 보낸) 값이고, 읽은 적이 없으면 기본값이다.
|
|
4516
|
+
|
|
4517
|
+
Raises:
|
|
4518
|
+
PropV2Error: 레벨 칸에 0~7 밖의 코드가 있을 때.
|
|
4519
|
+
"""
|
|
4520
|
+
from . import _propv2
|
|
4521
|
+
cls = type(self)
|
|
4522
|
+
base = self.__dict__.get("_il_log_snap") or cls()._pv2_log_now()
|
|
4523
|
+
out = []
|
|
4524
|
+
for cat, now in self._pv2_log_now().items():
|
|
4525
|
+
was = base[cat]
|
|
4526
|
+
body = {}
|
|
4527
|
+
if now[0] != was[0]:
|
|
4528
|
+
if not (isinstance(now[0], int) and 0 <= now[0] < len(cls._PV2_LOG_LEVELS)):
|
|
4529
|
+
raise _propv2.PropV2Error("LEVEL: unknown code %r" % (now[0],))
|
|
4530
|
+
body["LEVEL"] = cls._PV2_LOG_LEVELS[now[0]]
|
|
4531
|
+
if now[1] != was[1]:
|
|
4532
|
+
body["FILESIZE"] = int(now[1])
|
|
4533
|
+
if now[2] != was[2]:
|
|
4534
|
+
body["FILECOUNT"] = int(now[2])
|
|
4535
|
+
if body:
|
|
4536
|
+
out.append(dict({"_TYPE": "LOGGER", "CATEGORY": cat}, **body))
|
|
4537
|
+
return out
|
|
4538
|
+
|
|
4539
|
+
def _pv2_logger_sent(self) -> None:
|
|
4540
|
+
# 지금 로그 칸 값을 비교 기준으로 둔다(읽은 직후 · 보낸 직후)
|
|
4541
|
+
object.__setattr__(self, "_il_log_snap", self._pv2_log_now())
|
|
4542
|
+
|
|
4443
4543
|
def __init__(self, ba: bytes | bytearray | None = None) -> None:
|
|
4444
4544
|
"""서비스 속성 객체를 만든다.
|
|
4445
4545
|
|
|
@@ -4526,6 +4626,17 @@ class ILServiceProperty(_AutoAccessor):
|
|
|
4526
4626
|
offset += 24
|
|
4527
4627
|
self.hubPort = ba_pick_int(ba, offset, 10)
|
|
4528
4628
|
offset += 10
|
|
4629
|
+
# 왕복 보존: 원본과, 원본을 클라가 다시 짠 바이트. 직렬화는 원본 위에 클라 표현이 달라진 칸만 덮는다
|
|
4630
|
+
# ☠ 조회 경로를 실패시키지 않는다 - 다시 짜기가 실패하면(폭 검사 등) 원본 보관을 포기하고 옛 직렬화로 간다
|
|
4631
|
+
try:
|
|
4632
|
+
self._blobBuilt = self._build_blob()
|
|
4633
|
+
self._blobRaw = bytes(ba[:ILC.MIMQ_VO_SERVER_LEN])
|
|
4634
|
+
except Exception: # noqa: BLE001
|
|
4635
|
+
self._blobRaw = None
|
|
4636
|
+
|
|
4637
|
+
#: 클라가 아는 칸 ``(오프셋, 폭)``. 이 밖의 자리(하위호환 로그 106 · 풀 168 · 로그 3~4번째 232 · 예약 402)는 원본 그대로 간다.
|
|
4638
|
+
_BLOB_FIELDS = ((0, 100), (100, 6), (128, 20), (148, 10), (158, 10), (188, 2), (190, 15), (205, 5), (210, 2), (212, 15),
|
|
4639
|
+
(227, 5), (276, 2), (278, 2), (280, 2), (282, 2), (284, 36), (320, 48), (368, 24), (392, 10))
|
|
4529
4640
|
|
|
4530
4641
|
def get_serialized(self) -> bytes:
|
|
4531
4642
|
"""이 객체를 서버 규격의 **고정폭 바이트**로 직렬화한다.
|
|
@@ -4536,7 +4647,16 @@ class ILServiceProperty(_AutoAccessor):
|
|
|
4536
4647
|
Note:
|
|
4537
4648
|
라이브러리가 요청을 보낼 때 내부적으로 부른다. 응용이 직접 부를
|
|
4538
4649
|
일은 거의 없다.
|
|
4650
|
+
|
|
4651
|
+
**서버가 준 바이트로 만든 객체는 그 원본 위에 바뀐 칸만 덮는다** - 읽은 객체를 그대로 되보내면 같은 바이트가 나간다
|
|
4652
|
+
(다음 판). 클라가 모르는 자리(하위호환 로그 · 스레드 풀 · 로그 3~4번째 카테고리 · 예약)를 0 이나 기본값으로 덮지 않는다.
|
|
4539
4653
|
"""
|
|
4654
|
+
built = self._build_blob()
|
|
4655
|
+
raw = self.__dict__.get("_blobRaw")
|
|
4656
|
+
return built if raw is None else _patch_blob(raw, self._blobBuilt, built, type(self)._BLOB_FIELDS)
|
|
4657
|
+
|
|
4658
|
+
def _build_blob(self) -> bytes:
|
|
4659
|
+
# 필드만으로 짠 바이트(원본 없음 기준). 서버 원본이 있으면 get_serialized 가 원본 위에 바뀐 칸만 옮긴다
|
|
4540
4660
|
ba = bytearray(ILC.MIMQ_VO_SERVER_LEN)
|
|
4541
4661
|
offset = 0
|
|
4542
4662
|
ba_merge(self.ip, ba, offset, 100)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jetstream-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: Python client API for iLink M.O.M. (Message Oriented Middleware)
|
|
5
5
|
Author: snowjeans
|
|
6
6
|
License: Boost Software License - Version 1.0 - August 17th, 2003
|
|
@@ -60,6 +60,25 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
|
|
|
60
60
|
## 설치 방법
|
|
61
61
|
pip install jetstream-api
|
|
62
62
|
|
|
63
|
+
## 0.25.0 변경 - 서비스 속성 · 로거 Property v2(JSON) · 블롭 왕복 보존 (자바 v2.21.0 와 같음, 짝 엔진 7.0.1.3624 이상)
|
|
64
|
+
|
|
65
|
+
- **서비스 속성이 엔진 7 과 JSON 으로 오간다**(엔진 P5-2). ``ILAdminService.getProperty`` 는 SERVICE GET + LOGGER LIST(시스템 ·
|
|
66
|
+
클라이언트 로그 칸), ``setProperty`` 는 **바꾼 칸만** SERVICE ALTER + 바뀐 로그 카테고리마다 LOGGER ALTER 다. 6.x 엔진은 기존 블롭.
|
|
67
|
+
☠ **7.0.1.3623 이하 7.x 엔진에는 서비스 속성 조회 · 변경이 거절된다.**
|
|
68
|
+
- 더함: ``ILAdminService.setPropertyWithResult`` (``ILPropertyResult``, 로그 키는 ``LOGGER.SYS.LEVEL`` 모양, ``IP`` 는 ``RESTART`` -
|
|
69
|
+
재기동 뒤 반영, 나머지는 ``NOW``). 요청이 둘 이상이라 **원자적이지 않다** - 로거 변경이 거절되면 사유 뒤에
|
|
70
|
+
``[LOGGER <카테고리> 거절 - 이미 적용: SERVICE, ...]`` 가 붙는다(이미 적용된 쪽은 되돌리지 않는다).
|
|
71
|
+
- **서비스 · 큐관리자 속성 블롭 왕복 보존**: 읽은 객체를 그대로 ``setProperty`` 로 되보내면 엔진이 준 바이트가 그대로 나간다.
|
|
72
|
+
전에는 클라가 모르는 자리(하위호환 로그 칸 · 스레드 풀 칸 등)를 0 이나 기본값으로 덮었다.
|
|
73
|
+
- 문자열 상한을 엔진과 맞췄다: 큐 설명(``description``) **199바이트**(0.23.0 은 200), 서비스 IP 99 · 이름 47 · 허브 IP 23 · HOMEPATH 99
|
|
74
|
+
(엔진 7.0.1.3623 이상과 같다). 옛 판에서 저장된 더 긴 값은 읽기 · 되보내기에서 거절되지 않는다(읽을 때는 상한을 묻지 않는다).
|
|
75
|
+
- 서비스 ``aclType`` · ``relayType`` 은 0/1 만 받는다(그 밖은 엔진 7.0.1.3619 이상이 거절, 엔진 7 JSON 경로는 클라가 먼저 거절).
|
|
76
|
+
- 채널: 종류 · 방향을 바꿔 ``setChannelProperty`` 를 부르면 엔진 7 은 ``MIMQE_IMMUTABLE_PROPERTY (TYPE fixed at <현재 값>)`` 로 거절하고,
|
|
77
|
+
6.x 블롭은 조용히 옛 값을 유지한다(문서 정정 - 옛 문구 "다르면 NOT_FOUND" 는 틀렸다). TLS 채널을 JSON 으로 만들거나 바꾸는 것은 엔진
|
|
78
|
+
7.0.1.3617 이상에서 맞다(그 전 판은 기본 인증서를 채우지 않아 ``MIMQE_SSL_ERROR``).
|
|
79
|
+
- 세션: 엔진 7.0.1.3617 이상에서 ``destroyedTime`` 이 ``-1`` 이 아니면 끊긴 세션(보관 중)이다 - 상태는 ``EXCEPTION`` 일 수 있다.
|
|
80
|
+
그 전 판은 끊긴 세션도 ``-1`` 이라 가릴 수 없다.
|
|
81
|
+
|
|
63
82
|
## 0.24.0 변경 - 채널 · 세션 Property v2(JSON) · IBMMQ 채널 종류 (자바 v2.20.0 와 같음, 짝 엔진 7.0.1.3615 이상)
|
|
64
83
|
|
|
65
84
|
- **채널 관리가 엔진 7 과 JSON(Property v2) 으로 오간다**(엔진 P4). 함수 이름은 그대로 - ``createChannel`` · ``setChannelProperty`` ·
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|