Corin1998 commited on
Commit
71ca0c1
·
verified ·
1 Parent(s): be18f27

Update modules/utils.py

Browse files
Files changed (1) hide show
  1. modules/utils.py +64 -10
modules/utils.py CHANGED
@@ -5,16 +5,69 @@ import base64
5
  import hmac
6
  import hashlib
7
  from pathlib import Path
8
- from typing import Any, Dict, Optional
9
 
10
- # ====== 共通ディレクトリの用意 ======
11
- DATA_DIR = Path(os.getenv("DATA_DIR", "data"))
12
- EXPORT_DIR = DATA_DIR / "exports"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  def ensure_dirs() -> None:
15
- """必要なディレクトリを作成"""
16
- DATA_DIR.mkdir(parents=True, exist_ok=True)
17
- EXPORT_DIR.mkdir(parents=True, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  # ====== 簡易トラッキングトークン(追加依存なしのHMAC方式) ======
20
  _SECRET = os.getenv("TRACKING_SECRET", "dev-secret").encode("utf-8")
@@ -50,7 +103,6 @@ def verify_tracking_token(token: str) -> Optional[Dict[str, Any]]:
50
  part_json, part_sig = token.split(".", 1)
51
  b = _b64url_decode(part_json)
52
  expected = _sign(b)
53
- # 時間差攻撃対策の恒等比較
54
  if not hmac.compare_digest(part_sig, expected):
55
  return None
56
  return json.loads(b.decode("utf-8"))
@@ -58,11 +110,13 @@ def verify_tracking_token(token: str) -> Optional[Dict[str, Any]]:
58
  return None
59
 
60
  # ====== クリック/イベントの簡易ログ ======
61
- EVENTS_PATH = DATA_DIR / "events.jsonl"
 
62
 
63
  def log_event(event_type: str, payload: Dict[str, Any], meta: Optional[Dict[str, Any]] = None) -> None:
64
  """
65
  data/events.jsonl に1行追記。Spaceの Files タブから確認可能。
 
66
  """
67
  ensure_dirs()
68
  rec = {
@@ -71,5 +125,5 @@ def log_event(event_type: str, payload: Dict[str, Any], meta: Optional[Dict[str,
71
  "payload": payload or {},
72
  "meta": meta or {},
73
  }
74
- with open(EVENTS_PATH, "a", encoding="utf-8") as f:
75
  f.write(json.dumps(rec, ensure_ascii=False) + "\n")
 
5
  import hmac
6
  import hashlib
7
  from pathlib import Path
8
+ from typing import Any, Dict, Optional, List
9
 
10
+ # ------------------------------------------------------------
11
+ # 書き込みディレクトリの自動選択(/data /cache → /tmp → 最後に ./data
12
+ # ------------------------------------------------------------
13
+ _DATA_DIR: Optional[Path] = None
14
+ _EXPORT_DIR: Optional[Path] = None
15
+
16
+ def _is_writable(p: Path) -> bool:
17
+ try:
18
+ p.mkdir(parents=True, exist_ok=True)
19
+ testfile = p / ".w_test"
20
+ with open(testfile, "w", encoding="utf-8") as f:
21
+ f.write("ok")
22
+ testfile.unlink(missing_ok=True)
23
+ return True
24
+ except Exception:
25
+ return False
26
+
27
+ def _pick_writable_dir(candidates: List[Path]) -> Path:
28
+ for p in candidates:
29
+ if _is_writable(p):
30
+ return p
31
+ # 全滅時は最終手段として /tmp に落とす
32
+ fallback = Path("/tmp/agent_studio")
33
+ fallback.mkdir(parents=True, exist_ok=True)
34
+ return fallback
35
 
36
  def ensure_dirs() -> None:
37
+ """書き込み可能なデータディレクトリを決定して作成。"""
38
+ global _DATA_DIR, _EXPORT_DIR
39
+
40
+ if _DATA_DIR is not None and _EXPORT_DIR is not None:
41
+ return # 既に確定済み
42
+
43
+ # 優先順: 環境変数 DATA_DIR → /data → /cache → /tmp → ./data
44
+ env_dir = os.getenv("DATA_DIR")
45
+ candidates = []
46
+ if env_dir:
47
+ candidates.append(Path(env_dir))
48
+ candidates.extend([
49
+ Path("/data/agent_studio"),
50
+ Path("/cache/agent_studio"),
51
+ Path("/tmp/agent_studio"),
52
+ Path("data"), # 最後に相対パス
53
+ ])
54
+
55
+ chosen = _pick_writable_dir(candidates)
56
+ export = chosen / "exports"
57
+
58
+ chosen.mkdir(parents=True, exist_ok=True)
59
+ export.mkdir(parents=True, exist_ok=True)
60
+
61
+ _DATA_DIR = chosen
62
+ _EXPORT_DIR = export
63
+
64
+ def data_dir() -> Path:
65
+ ensure_dirs()
66
+ return _DATA_DIR # type: ignore
67
+
68
+ def export_dir() -> Path:
69
+ ensure_dirs()
70
+ return _EXPORT_DIR # type: ignore
71
 
72
  # ====== 簡易トラッキングトークン(追加依存なしのHMAC方式) ======
73
  _SECRET = os.getenv("TRACKING_SECRET", "dev-secret").encode("utf-8")
 
103
  part_json, part_sig = token.split(".", 1)
104
  b = _b64url_decode(part_json)
105
  expected = _sign(b)
 
106
  if not hmac.compare_digest(part_sig, expected):
107
  return None
108
  return json.loads(b.decode("utf-8"))
 
110
  return None
111
 
112
  # ====== クリック/イベントの簡易ログ ======
113
+ def _events_path() -> Path:
114
+ return data_dir() / "events.jsonl"
115
 
116
  def log_event(event_type: str, payload: Dict[str, Any], meta: Optional[Dict[str, Any]] = None) -> None:
117
  """
118
  data/events.jsonl に1行追記。Spaceの Files タブから確認可能。
119
+ 書き込み場所は ensure_dirs() により自動選択される。
120
  """
121
  ensure_dirs()
122
  rec = {
 
125
  "payload": payload or {},
126
  "meta": meta or {},
127
  }
128
+ with open(_events_path(), "a", encoding="utf-8") as f:
129
  f.write(json.dumps(rec, ensure_ascii=False) + "\n")