DEPO Firebird: путь к базе — и строкой подключения Fancy целиком (база на другом компьютере)
Поле пути в мастере и в «Таблицах обмена» принимает строку подключения из настройки Fancy: «сервер:путь», «сервер/порт:путь», «\\сервер\D:\путь», «\\сервер\D$\путь», «inet://сервер:порт/путь» — адрес и порт bj берёт из неё (в мастере поля заполняются сразу при вставке). Сетевая папка «\\сервер\папка\…» — ошибка с подсказкой: Firebird открывает базу только на своём диске, адрес — компьютер с сервером Firebird. Проверено мастером на копии базы: пустой адрес + «127.0.0.1/3050:путь» — подготовка и BJ_PING. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -77,7 +77,25 @@ func (h *setupHandlers) saveFancyDepoTables(w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
s := h.rc.Snapshot().Fancy
|
||||
db := strings.TrimSpace(r.FormValue("depo_database"))
|
||||
if db != "" && !validDBName(db) {
|
||||
if s.IsFirebird() && db != "" { // путь к базе на сервере Firebird или строка подключения Fancy целиком
|
||||
host, p, path, err := fbSplitConn(db)
|
||||
if err != nil {
|
||||
setupFlash(w, r, "Таблицы DEPO: "+err.Error())
|
||||
return
|
||||
}
|
||||
if !validFBPath(path) {
|
||||
setupFlash(w, r, "Таблицы DEPO: путь к базе — без кавычек, ; ? и #")
|
||||
return
|
||||
}
|
||||
if host != "" && (host != s.Server || (p != 0 && p != s.Port)) {
|
||||
s.Server = host
|
||||
if p != 0 {
|
||||
s.Port = p
|
||||
}
|
||||
s.DepoJobCheck, s.DepoJobCheckOK = "", false
|
||||
}
|
||||
db = path
|
||||
} else if db != "" && !validDBName(db) {
|
||||
setupFlash(w, r, "Таблицы DEPO: имя базы — только латинские буквы/цифры/_, начинать с буквы")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -468,3 +468,50 @@ func fbErr(orig, sent string, err error) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
fbDriveRe = regexp.MustCompile(`^[A-Za-z]:[\\/]`)
|
||||
fbHostRe = regexp.MustCompile(`^([A-Za-z0-9._\-]{2,}|\[[0-9A-Fa-f:]+\])(?:/(\d{1,5}))?:(.+)$`)
|
||||
fbUNCRe = regexp.MustCompile(`^\\\\([^\\/]+)[\\/](.+)$`)
|
||||
fbAdmShRe = regexp.MustCompile(`^([A-Za-z])\$[\\/](.*)$`)
|
||||
fbInetURLRe = regexp.MustCompile(`(?i)^inet[46]?://([^/:]+)(?::(\d{1,5}))?/(.+)$`)
|
||||
)
|
||||
|
||||
// fbSplitConn — строка подключения Fancy к базе Firebird целиком: «сервер:путь», «сервер/порт:путь»,
|
||||
// «\\сервер\D:\путь», «\\сервер\D$\путь», «inet://сервер:порт/путь». База обычно на другом компьютере — на
|
||||
// том, где работает сервер Firebird; bj подключается к нему по сети, а путь — на диске этого компьютера.
|
||||
// host="" — указан только путь (сервер — в отдельном поле). Сетевую папку (\\сервер\папка\…) Firebird не
|
||||
// открывает — ошибка с подсказкой.
|
||||
func fbSplitConn(s string) (host string, port int, path string, err error) {
|
||||
s = strings.TrimSpace(s)
|
||||
switch {
|
||||
case fbDriveRe.MatchString(s) || strings.HasPrefix(s, "/") || !strings.ContainsAny(s, `:\/`):
|
||||
return "", 0, s, nil // путь на сервере или псевдоним
|
||||
case fbInetURLRe.MatchString(s):
|
||||
m := fbInetURLRe.FindStringSubmatch(s)
|
||||
port, _ = strconv.Atoi(m[2])
|
||||
path = m[3]
|
||||
if !fbDriveRe.MatchString(path) && !strings.ContainsAny(path, `\/`) { // inet://host/alias
|
||||
return m[1], port, path, nil
|
||||
}
|
||||
if !fbDriveRe.MatchString(path) {
|
||||
path = "/" + path
|
||||
}
|
||||
return m[1], port, path, nil
|
||||
case fbUNCRe.MatchString(s):
|
||||
m := fbUNCRe.FindStringSubmatch(s)
|
||||
rest := m[2]
|
||||
if fbDriveRe.MatchString(rest) { // \\сервер\D:\путь — так Fancy пишет подключение по именованным каналам
|
||||
return m[1], 0, rest, nil
|
||||
}
|
||||
if a := fbAdmShRe.FindStringSubmatch(rest); a != nil { // \\сервер\D$\путь — административный общий ресурс
|
||||
return m[1], 0, strings.ToUpper(a[1]) + `:\` + a[2], nil
|
||||
}
|
||||
return "", 0, "", fmt.Errorf("%s — сетевая папка: Firebird не открывает базы по сети как файл. Укажите компьютер %s в поле «Адрес сервера» (на нём должен работать сервер Firebird), а путь — на его диске, например D:\\Fancy\\DEPO.GDB, — как в подключении Fancy", s, m[1])
|
||||
case fbHostRe.MatchString(s):
|
||||
m := fbHostRe.FindStringSubmatch(s)
|
||||
port, _ = strconv.Atoi(m[2])
|
||||
return strings.Trim(m[1], "[]"), port, m[3], nil
|
||||
}
|
||||
return "", 0, s, nil
|
||||
}
|
||||
|
||||
@@ -115,3 +115,31 @@ func TestFBScriptsMatchDeploy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFBSplitConn(t *testing.T) {
|
||||
cases := []struct {
|
||||
in, host string
|
||||
port int
|
||||
path string
|
||||
bad bool
|
||||
}{
|
||||
{`D:\Fancy\Bases\DEPO.GDB`, "", 0, `D:\Fancy\Bases\DEPO.GDB`, false},
|
||||
{`/var/db/depo.fdb`, "", 0, `/var/db/depo.fdb`, false},
|
||||
{`DEPO`, "", 0, `DEPO`, false},
|
||||
{`10.0.0.5:D:\Fancy\Bases\DEPO.GDB`, "10.0.0.5", 0, `D:\Fancy\Bases\DEPO.GDB`, false},
|
||||
{`srv-depo/3051:D:\Show Depo\Bases\SPI_DEPO.GDB`, "srv-depo", 3051, `D:\Show Depo\Bases\SPI_DEPO.GDB`, false},
|
||||
{`fbsrv:/var/db/depo.fdb`, "fbsrv", 0, `/var/db/depo.fdb`, false},
|
||||
{`fbsrv:DEPO`, "fbsrv", 0, `DEPO`, false},
|
||||
{`\\SRV-DEPO\D:\Fancy\DEPO.GDB`, "SRV-DEPO", 0, `D:\Fancy\DEPO.GDB`, false},
|
||||
{`\\SRV-DEPO\d$\Fancy\DEPO.GDB`, "SRV-DEPO", 0, `D:\Fancy\DEPO.GDB`, false},
|
||||
{`inet://10.0.0.5:3050/D:\Fancy\DEPO.GDB`, "10.0.0.5", 3050, `D:\Fancy\DEPO.GDB`, false},
|
||||
{`inet://10.0.0.5/depo`, "10.0.0.5", 0, `depo`, false},
|
||||
{`\\SRV-DEPO\Bases\DEPO.GDB`, "", 0, "", true},
|
||||
}
|
||||
for _, c := range cases {
|
||||
h, p, path, err := fbSplitConn(c.in)
|
||||
if (err != nil) != c.bad || h != c.host || p != c.port || path != c.path {
|
||||
t.Errorf("fbSplitConn(%q) = %q, %d, %q, %v", c.in, h, p, path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ func registerIgateAdmin(mux *http.ServeMux, rc *RuntimeConfig) {
|
||||
return
|
||||
}
|
||||
depoDB := strings.TrimSpace(r.FormValue("depo_db"))
|
||||
if depoDB != "" && !validDBName(depoDB) {
|
||||
if depoDB != "" && !validDBName(depoDB) && !(s.Fancy.IsFirebird() && validFBPath(depoDB)) { // у Firebird — путь к базе
|
||||
jsonOut(w, map[string]any{"ok": false, "error": "имя базы DEPO — латинские буквы, цифры и _"})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -156,10 +156,10 @@
|
||||
<div class="dq-grid dq-srv">
|
||||
<label>Адрес сервера<input type="text" name="server" data-need="адрес сервера DEPO" value="{{.Settings.Fancy.Server}}" placeholder="IP-адрес или имя\экземпляр" required autofocus spellcheck="false"></label>
|
||||
<label>Порт<input type="text" name="port" value="{{if .Settings.Fancy.Port}}{{.Settings.Fancy.Port}}{{else if $pg}}5432{{else if $fb}}3050{{else}}1433{{end}}" inputmode="numeric"></label>
|
||||
<label><span data-nofb>Имя базы</span><span data-fb>Путь к базе</span><input type="text" name="depo_database" data-need="имя базы DEPO" value="{{.Settings.Fancy.DepoDatabase}}" placeholder="{{if $fb}}D:\Fancy\DEPO.GDB или псевдоним{{else}}как называется на сервере{{end}}" required {{if not $fb}}pattern="[A-Za-z][A-Za-z0-9_]*" {{end}}title="латинские буквы, цифры и _, начинается с буквы" spellcheck="false"></label>
|
||||
<label><span data-nofb>Имя базы</span><span data-fb>Путь к базе</span><input type="text" name="depo_database" data-need="имя базы DEPO" value="{{.Settings.Fancy.DepoDatabase}}" placeholder="{{if $fb}}D:\Fancy\DEPO.GDB или 10.0.0.5:D:\Fancy\DEPO.GDB{{else}}как называется на сервере{{end}}" required {{if not $fb}}pattern="[A-Za-z][A-Za-z0-9_]*" {{end}}title="латинские буквы, цифры и _, начинается с буквы" spellcheck="false"></label>
|
||||
</div>
|
||||
<p class="dq-note" data-nofb>Точное имя базы учёта DEPO — bj будет работать только с ней. Перед подготовкой bj проверит, что в ней есть учётные таблицы DEPO, и в чужую базу ничего не запишет.</p>
|
||||
<p class="dq-note" data-fb>Путь к файлу базы учёта на сервере Firebird — как в подключении Fancy (например, <span class="dq-mono">D:\Fancy\Bases\DEPO.GDB</span>), или её псевдоним из aliases.conf. Перед подготовкой bj проверит, что это база DEPO и функции Fancy на сервере доступны.</p>
|
||||
<p class="dq-note" data-fb>База обычно на другом компьютере: «Адрес сервера» — компьютер, где работает сервер Firebird, путь — на его диске (например, <span class="dq-mono">D:\Fancy\Bases\DEPO.GDB</span>) или псевдоним из aliases.conf. Можно вставить строку подключения из настройки Fancy целиком — <span class="dq-mono">10.0.0.5:D:\Fancy\Bases\DEPO.GDB</span>, адрес и порт bj возьмёт из неё. Сетевую папку (\\компьютер\папка) Firebird не открывает. Перед подготовкой bj проверит, что это база DEPO и функции Fancy на сервере доступны.</p>
|
||||
</section>
|
||||
|
||||
<section class="dq-s">
|
||||
@@ -247,7 +247,7 @@
|
||||
if(['1433','5432','3050'].indexOf(f.port.value)>=0) f.port.value={mssql:'1433',postgres:'5432',firebird:'3050'}[t];
|
||||
f.admin_user.placeholder=pg?'postgres':fb?'SYSDBA':'sa';
|
||||
var dbi=f.depo_database; // Firebird: путь к файлу базы или псевдоним, а не имя
|
||||
if(fb){ dbi.removeAttribute('pattern'); dbi.placeholder='D:\\Fancy\\DEPO.GDB или псевдоним'; }
|
||||
if(fb){ dbi.removeAttribute('pattern'); dbi.placeholder='D:\\Fancy\\DEPO.GDB или 10.0.0.5:D:\\Fancy\\DEPO.GDB'; }
|
||||
else { dbi.setAttribute('pattern','[A-Za-z][A-Za-z0-9_]*'); dbi.placeholder='как называется на сервере'; }
|
||||
if(fb&&f.bj_user.value==='bj_user') f.bj_user.value='SYSDBA_BJ'; else if(!fb&&f.bj_user.value==='SYSDBA_BJ') f.bj_user.value='bj_user';
|
||||
var jn=f.depo_job_name, dbv=(f.depo_database.value||'').trim(); // имя задания — по базе, пока не поправили руками
|
||||
@@ -270,6 +270,14 @@
|
||||
else { pre.textContent=''; pre.dataset.msg=x.t.trim().replace(/^./,function(c){return c.toUpperCase()})+' — скрипт появится здесь.'; } })
|
||||
.catch(function(){ if(my!==seq) return; last=''; pre.classList.remove('dq-busy'); pre.textContent=''; pre.dataset.msg='Не получилось собрать скрипт — обновите страницу.'; });
|
||||
}
|
||||
function splitFB(){ // строка подключения Fancy целиком: «сервер[/порт]:путь», «\\сервер\D:\путь», «\\сервер\D$\путь»
|
||||
if(f.db_type.value!=='firebird') return;
|
||||
var v=f.depo_database.value.trim(), m;
|
||||
if(/^[A-Za-z]:[\\/]/.test(v)) return;
|
||||
if((m=/^\\\\([^\\/]+)[\\/]([A-Za-z]):?\$?[\\/](.*)$/.exec(v))){ f.server.value=m[1]; f.depo_database.value=m[2].toUpperCase()+':\\'+m[3]; return; }
|
||||
if((m=/^([A-Za-z0-9._-]{2,})(?:\/(\d{1,5}))?:(.+)$/.exec(v))){ f.server.value=m[1]; if(m[2]) f.port.value=m[2]; f.depo_database.value=m[3]; }
|
||||
}
|
||||
f.depo_database.addEventListener('change', function(){ splitFB(); changed(); });
|
||||
function changed(){ sync(); clearTimeout(timer); timer=setTimeout(load, 350); }
|
||||
f.depo_job_name.addEventListener('input', function(){ this.dataset.auto=this.value.trim()?'0':'1'; });
|
||||
f.addEventListener('input', changed); f.addEventListener('change', changed);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<form method="post" action="/admin/setup/fancy/depo-tables" style="margin-top:10px;display:grid;gap:10px;max-width:720px">
|
||||
<input type="hidden" name="section" value="sec-fancy-depo-tables">
|
||||
<label>База DEPO
|
||||
<input type="text" name="depo_database" value="{{.Settings.Fancy.DepoDatabase}}" placeholder="{{.DepoTables.DB}}" pattern="[A-Za-z][A-Za-z0-9_]*" style="width:100%"></label>
|
||||
<input type="text" name="depo_database" value="{{.Settings.Fancy.DepoDatabase}}" placeholder="{{if .Settings.Fancy.IsFirebird}}D:\Fancy\Bases\DEPO.GDB или 10.0.0.5:D:\Fancy\Bases\DEPO.GDB{{else}}{{.DepoTables.DB}}{{end}}" {{if not .Settings.Fancy.IsFirebird}}pattern="[A-Za-z][A-Za-z0-9_]*" {{end}}style="width:100%"></label>
|
||||
<label>Признак ИИС в названии брокерского договора <span class="muted" style="font-weight:400">(с чего начинается номер договора ИИС в DEPO; несколько — через запятую)</span>
|
||||
<input type="text" name="iis_contract_marker" value="{{.Settings.Fancy.IISContractMarker}}" placeholder="БРИИС" style="width:100%"></label>
|
||||
<label style="display:flex;gap:8px;align-items:flex-start;font-weight:600"><input type="radio" name="depo_tables_mode" value="auto" {{if eq .Settings.Fancy.DepoTablesMode "auto"}}checked{{end}}> <span>Создаёт bj <span class="muted" style="font-weight:400">— вводите логин с правами на создание таблиц в базе DEPO. Он используется один раз и не сохраняется; bj заодно выдаст права своему логину.</span></span></label>
|
||||
|
||||
@@ -248,10 +248,20 @@ func (h *setupHandlers) depoSetupForm(r *http.Request) (FancyMSSQLSettings, stri
|
||||
return s, "", agent, "укажите имя базы DEPO — как она называется на сервере"
|
||||
}
|
||||
if dbType == "firebird" {
|
||||
if !validFBPath(db) {
|
||||
host, p, path, err := fbSplitConn(db) // строка подключения Fancy целиком: «сервер:путь» — сервер из неё
|
||||
if err != nil {
|
||||
return s, "", agent, err.Error()
|
||||
}
|
||||
if host != "" {
|
||||
s.Server = host
|
||||
if p != 0 {
|
||||
s.Port = p
|
||||
}
|
||||
}
|
||||
if !validFBPath(path) {
|
||||
return s, "", agent, "путь к базе DEPO — без кавычек, ; ? и #"
|
||||
}
|
||||
return s, db, agent, ""
|
||||
return s, path, agent, ""
|
||||
}
|
||||
if !validDBName(db) {
|
||||
return s, "", agent, "имя базы DEPO — только латинские буквы, цифры и _, начинается с буквы"
|
||||
|
||||
Reference in New Issue
Block a user