fix: 포트 충돌 회피 — note_bridge 8098, intent_service 8099

Jellyfin(8096), OrbStack(8097) 포트 충돌으로 변경.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-19 13:53:55 +09:00
parent dc08d29509
commit c2257d3a86
2709 changed files with 619549 additions and 10 deletions

View File

@@ -0,0 +1,125 @@
import json
import logging
import os
"""
This configuration parsing code was just copied from my plann library (and will be removed from there at some point in the future). Test coverage is poor as for now.
"""
## This is being moved from my plann library. The code itself will be introduced into caldav 2.0, but proper test code and documentation will come in a later release (2.1?)
## TODO TODO TODO - write test code for all the corner cases
## TODO TODO TODO - write documentation of config format
def expand_config_section(config, section="default", blacklist=None):
"""
In the "normal" case, will return [ section ]
We allow:
* * includes all sections in config file
* "Meta"-sections in the config file with the keyword "contains" followed by a list of section names
* Recursive "meta"-sections
* Glob patterns (work_* for all sections starting with work_)
* Glob patterns in "meta"-sections
"""
## Optimizating for a special case. The results should be the same without this optimization.
if section == "*":
return [x for x in config if not config[x].get("disable", False)]
## If it's not a glob-pattern ...
if set(section).isdisjoint(set("[*?")):
## If it's referring to a "meta section" with the "contains" keyword
if "contains" in config[section]:
results = []
if not blacklist:
blacklist = set()
blacklist.add(section)
for subsection in config[section]["contains"]:
if not subsection in results and not subsection in blacklist:
for recursivesubsection in expand_config_section(
config, subsection, blacklist
):
if not recursivesubsection in results:
results.append(recursivesubsection)
return results
else:
## Disabled sections should be ignored
if config.get("section", {}).get("disable", False):
return []
## NORMAL CASE - return [ section ]
return [section]
## section name is a glob pattern
matching_sections = [x for x in config if fnmatch(x, section)]
results = set()
for s in matching_sections:
if set(s).isdisjoint(set("[*?")):
results.update(expand_config_section(config, s))
else:
## Section names shouldn't contain []?* ... but in case they do ... don't recurse
results.add(s)
return results
def config_section(config, section="default"):
if section in config and "inherits" in config[section]:
ret = config_section(config, config[section]["inherits"])
else:
ret = {}
if section in config:
ret.update(config[section])
return ret
def read_config(fn, interactive_error=False):
if not fn:
cfgdir = f"{os.environ.get('HOME', '/')}/.config/"
for config_file in (
f"{cfgdir}/caldav/calendar.conf",
f"{cfgdir}/caldav/calendar.yaml",
f"{cfgdir}/caldav/calendar.json",
f"{cfgdir}/calendar.conf",
"/etc/calendar.conf",
"/etc/caldav/calendar.conf",
):
cfg = read_config(config_file)
if cfg:
return cfg
return None
## This can probably be refactored into fewer lines ...
try:
try:
with open(fn, "rb") as config_file:
return json.load(config_file)
except json.decoder.JSONDecodeError:
## Late import, wrapped in try/except. yaml is external module,
## and not included in the requirements as for now.
try:
import yaml
try:
with open(fn, "rb") as config_file:
return yaml.load(config_file, yaml.Loader)
except yaml.scanner.ScannerError:
logging.error(
f"config file {fn} exists but is neither valid json nor yaml. Check the syntax."
)
except ImportError:
logging.error(
f"config file {fn} exists but is not valid json, and pyyaml is not installed."
)
except FileNotFoundError:
## File not found
logging.info("no config file found")
except ValueError:
if interactive_error:
logging.error(
"error in config file. Be aware that the interactive configuration will ignore and overwrite the current broken config file",
exc_info=True,
)
else:
logging.error("error in config file. It will be ignored", exc_info=True)
return {}