SunsetLog 0.0.2__tar.gz → 0.0.3__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.
@@ -1,2 +1,3 @@
1
1
  *.pyc
2
2
  example.py
3
+ /.vscode
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: SunsetLog
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Add your description here
5
5
  Requires-Python: <3.15,>=3.10
6
6
  Requires-Dist: httpx>=0.28.1
@@ -108,17 +108,21 @@ class SunsetLogClient:
108
108
  *,
109
109
  channels: str | list[str] | None = None,
110
110
  gang: int = 1,
111
+ job: int = 1,
111
112
  q: str = "",
112
113
  from_offset: int = 0,
113
114
  mode: str = "exact",
114
115
  operator: str = "and",
116
+ order: str = "desc",
117
+ hidden: str = "exclude",
115
118
  ) -> SearchResponse:
116
119
  """
117
120
  Search logs. GET /search.
118
121
  channels: single channel name or comma-separated list.
122
+ order: "desc" (newest first) or "asc" (oldest first).
119
123
  """
120
124
  if channels is None:
121
- channel_list = await self.get_channel_list(gang=gang)
125
+ channel_list = await self.get_channel_list(gang=gang, job=job)
122
126
  indexes = [c["index"] for c in channel_list.get("channels", [])]
123
127
  channels = ",".join(indexes) if indexes else "gang_glitch_locker1"
124
128
  elif isinstance(channels, list):
@@ -130,8 +134,11 @@ class SunsetLogClient:
130
134
  "from": from_offset,
131
135
  "mode": mode,
132
136
  "operator": operator,
137
+ "hidden": hidden,
133
138
  "channels": channels,
139
+ "order": order,
134
140
  "gang": gang,
141
+ "job": job,
135
142
  }
136
143
  r = await client.get("/search", params=params)
137
144
  if r.status_code != 200:
@@ -0,0 +1,86 @@
1
+ """
2
+ Reverse proxy for log-api.vmp.ir, meant to run ON A SERVER INSIDE IRAN
3
+ that already has direct access to the real API. Uses SunsetLogClient
4
+ (this library) internally instead of calling the API directly.
5
+
6
+ An external server (outside Iran, where log-api.vmp.ir is blocked) can then
7
+ point SunsetLogClient's base_url at THIS proxy instead of the real API.
8
+ No separate proxy key: the caller's own site token (the same one used
9
+ against the real API) is forwarded upstream as-is.
10
+
11
+ Run directly (host/port configurable via env vars, no uvicorn CLI needed):
12
+ pip install fastapi uvicorn
13
+ export PROXY_HOST=0.0.0.0 # your Iran server's bind address
14
+ export PROXY_PORT=8000
15
+ python proxy_server.py
16
+
17
+ In /docs, click the "Authorize" lock button at the top and paste just the
18
+ site token (no "Bearer " prefix needed there) — Swagger adds it for you.
19
+ """
20
+
21
+ import os
22
+ from typing import Annotated
23
+
24
+ import httpx
25
+ from fastapi import Depends, FastAPI, HTTPException, Query
26
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
27
+
28
+ UPSTREAM_BASE_URL = "https://log-api.vmp.ir"
29
+
30
+ app = FastAPI()
31
+ bearer_scheme = HTTPBearer()
32
+
33
+
34
+ async def _forward(path: str, params: dict, token: str) -> dict:
35
+ async with httpx.AsyncClient(base_url=UPSTREAM_BASE_URL, timeout=30.0) as client:
36
+ r = await client.get(
37
+ path, params=params, headers={"Authorization": f"Bearer {token}"}
38
+ )
39
+ if r.status_code != 200:
40
+ raise HTTPException(status_code=r.status_code, detail=r.text)
41
+ return r.json()
42
+
43
+
44
+ @app.get("/user/getChannels")
45
+ async def get_channels(
46
+ creds: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)],
47
+ gang: int = 1,
48
+ job: int = 1,
49
+ ):
50
+ return await _forward(
51
+ "/user/getChannels", {"gang": gang, "job": job}, creds.credentials
52
+ )
53
+
54
+
55
+ @app.get("/search")
56
+ async def search(
57
+ creds: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)],
58
+ q: str = "",
59
+ from_offset: int = Query(0, alias="from"),
60
+ mode: str = "exact",
61
+ operator: str = "and",
62
+ channels: str = "",
63
+ gang: int = 1,
64
+ ):
65
+ return await _forward(
66
+ "/search",
67
+ {
68
+ "q": q,
69
+ "from": from_offset,
70
+ "mode": mode,
71
+ "operator": operator,
72
+ "channels": channels,
73
+ "gang": gang,
74
+ },
75
+ creds.credentials,
76
+ )
77
+
78
+
79
+ if __name__ == "__main__":
80
+ import uvicorn
81
+
82
+ uvicorn.run(
83
+ app,
84
+ host=os.environ.get("PROXY_HOST", "0.0.0.0"),
85
+ port=int(os.environ.get("PROXY_PORT", "8000")),
86
+ )
@@ -0,0 +1,31 @@
1
+ """
2
+ Run this on the EXTERNAL server (outside Iran) to test that the Iran-side
3
+ proxy (see proxy_server.py) is reachable and working.
4
+
5
+ export PROXY_BASE_URL=http://your-iran-server-ip:8000
6
+ export PROXY_ACCESS_KEY=same_secret_set_on_the_proxy
7
+ python test_via_proxy.py
8
+ """
9
+
10
+ import asyncio
11
+ import os
12
+
13
+ from SunsetLog import SunsetLogAPIError, SunsetLogClient
14
+
15
+
16
+ async def main() -> None:
17
+ base_url = os.environ["PROXY_BASE_URL"]
18
+ access_key = os.environ["PROXY_ACCESS_KEY"]
19
+
20
+ async with SunsetLogClient(access_key, base_url=base_url) as client:
21
+ try:
22
+ channels = await client.get_channel_list(gang=1, job=1)
23
+ print(f"OK - got {len(channels['channels'])} channels")
24
+ for c in channels["channels"][:5]:
25
+ print(f" {c['id']:>6} {c['index']}")
26
+ except SunsetLogAPIError as e:
27
+ print(f"FAILED: {e} (status={e.status_code}, body={e.body})")
28
+
29
+
30
+ if __name__ == "__main__":
31
+ asyncio.run(main())
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "SunsetLog"
3
- version = "0.0.2"
3
+ version = "0.0.3"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.15"
@@ -85,7 +85,7 @@ wheels = [
85
85
 
86
86
  [[package]]
87
87
  name = "sunsetlog"
88
- version = "0.0.2"
88
+ version = "0.0.3"
89
89
  source = { editable = "." }
90
90
  dependencies = [
91
91
  { name = "httpx" },
File without changes
File without changes
File without changes
File without changes