Removed old impl

This commit is contained in:
2026-06-12 04:51:38 +08:00
parent 4fcd58b5ed
commit f532ada7c4
63 changed files with 717 additions and 1359 deletions
+85
View File
@@ -0,0 +1,85 @@
package closure
import (
"context"
"errors"
"time"
)
func NewCompileCache(workers int) *CompileCache {
c := &CompileCache{
client: NewClientFromEnv(),
states: make(map[string]CompileState),
results: make(map[string][]byte),
errors: make(map[string]error),
jobs: make(chan CompileJob, 128),
}
for i := 0; i < workers; i++ {
go c.worker()
}
return c
}
func (c *CompileCache) Get(hash string) ([]byte, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.states[hash] != CompileReady {
return nil, false
}
return c.results[hash], true
}
func (c *CompileCache) Enqueue(job CompileJob) {
c.mu.Lock()
switch c.states[job.Hash] {
case CompilePending, CompileReady:
c.mu.Unlock()
return
}
c.states[job.Hash] = CompilePending
c.mu.Unlock()
select {
case c.jobs <- job:
default:
// Queue full. Don't block request path.
c.mu.Lock()
c.states[job.Hash] = CompileMissing
c.errors[job.Hash] = errors.New("compile queue full")
c.mu.Unlock()
}
}
func (c *CompileCache) worker() {
for job := range c.jobs {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
req := CompileRequest{
ExternSources: job.ExternSources,
JSSources: job.JSSources,
Defines: job.Defines,
}
c.client.DebugPrintCurl(ctx, req)
out, err := c.client.Compile(ctx, req)
cancel()
c.mu.Lock()
if err != nil {
c.states[job.Hash] = CompileFailed
c.errors[job.Hash] = err
} else {
c.states[job.Hash] = CompileReady
c.results[job.Hash] = out
delete(c.errors, job.Hash)
}
c.mu.Unlock()
}
}
+107
View File
@@ -0,0 +1,107 @@
package closure
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"time"
)
type Client struct {
endpoint string
http *http.Client
}
func NewClientFromEnv() *Client {
endpoint := os.Getenv("CLOSURE_ENDPOINT")
if endpoint == "" {
endpoint = "http://closure-svc:8080/compile"
}
return &Client{
endpoint: endpoint,
http: &http.Client{
Timeout: 70 * time.Second,
},
}
}
func (c *Client) Compile(ctx context.Context, reqBody CompileRequest) ([]byte, error) {
body, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(
ctx,
http.MethodPost,
c.endpoint,
bytes.NewReader(body),
)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.http.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode/100 != 2 {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
return nil, fmt.Errorf("closure failed: %s: %s", resp.Status, body)
}
return io.ReadAll(resp.Body)
}
func (c *Client) DebugPrintCurl(ctx context.Context, reqBody CompileRequest) {
if os.Getenv("CLOSURE_DEBUG_CURL") == "" {
return
}
body, err := json.MarshalIndent(reqBody, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "closure debug: marshal payload failed: %v\n", err)
return
}
tmpDir := os.Getenv("CLOSURE_DEBUG_DIR")
if tmpDir == "" {
tmpDir = os.TempDir()
}
path := filepath.Join(
tmpDir,
fmt.Sprintf("closure-request-%d.json", time.Now().UnixNano()),
)
if err := os.WriteFile(path, body, 0o600); err != nil {
fmt.Fprintf(os.Stderr, "closure debug: write payload failed: %v\n", err)
return
}
fmt.Fprintf(
os.Stderr,
"closure debug curl:\n curl -v -X POST %s -H 'Content-Type: application/json' --data-binary @%s\n",
shellQuote(c.endpoint),
shellQuote(path),
)
if deadline, ok := ctx.Deadline(); ok {
fmt.Fprintf(os.Stderr, "closure debug deadline: %s\n", deadline.Format(time.RFC3339Nano))
}
}
func shellQuote(s string) string {
return strconv.Quote(s)
}
+41
View File
@@ -0,0 +1,41 @@
package closure
import "sync"
type CompileState int
const (
CompileMissing CompileState = iota
CompilePending
CompileReady
CompileFailed
)
type CompileRequest struct {
ExternSources []SourceInput `json:"externSources,omitempty"`
JSSources []SourceInput `json:"jsSources"`
Defines map[string]any `json:"defines,omitempty"`
}
type SourceInput struct {
Name string `json:"name"`
Source string `json:"source"`
}
type CompileJob struct {
Hash string
Mode string
ExternSources []SourceInput
JSSources []SourceInput
Defines map[string]any
}
type CompileCache struct {
client *Client
mu sync.Mutex
states map[string]CompileState
results map[string][]byte
errors map[string]error
jobs chan CompileJob
}
@@ -2,5 +2,5 @@ package generated
const (
IMAGE_TAG = "dev"
Timestamp = "20260610.201739"
Timestamp = "20260611.192429"
)
@@ -1,7 +1,7 @@
// Code generated by botan-gen; DO NOT EDIT.
// Code generated by classmap-gen; DO NOT EDIT.
package generated
import "github.com/tgckpg/botanres-go/internal/classmap"
import "github.com/tgckpg/resolver-go/internal/classmap"
var ClassMap = &classmap.Map{
Symbols: map[string]classmap.Symbol{
@@ -84,9 +84,9 @@ var ClassMap = &classmap.Map{
"Astro.Common.Element": {Name: "Astro.Common.Element", Kind: "class", Parent: "Astro.Common", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
"Astro.Common.Element.Footer": {Name: "Astro.Common.Element.Footer", Kind: "class", Parent: "Astro.Common.Element", Imports: []string(nil), Resource: classmap.Resource{Src: "Astro/Common/Element/Footer.js", JSHash: "80f69d85c399bdc04d3b2055d1ebbe9ee77a852a", CSSHash: "c26f4238a6a4f2fc0bcbd9ac86141d12522552a4"}},
"Astro.Mechanism": {Name: "Astro.Mechanism", Kind: "class", Parent: "Astro", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
"Astro.Mechanism.CharacterCloud": {Name: "Astro.Mechanism.CharacterCloud", Kind: "class", Parent: "Astro.Mechanism", Imports: []string{"Dandelion"}, Resource: classmap.Resource{Src: "Astro/Mechanism/CharacterCloud.js", JSHash: "540a2085798928418a54e10d56bc037863ee57a9", CSSHash: "7cae98eaf8e3d5d1cd7fadaa6806ce3d65d74d92"}},
"Astro.Mechanism.CharacterCloud": {Name: "Astro.Mechanism.CharacterCloud", Kind: "class", Parent: "Astro.Mechanism", Imports: []string{"Dandelion"}, Resource: classmap.Resource{Src: "Astro/Mechanism/CharacterCloud.js", JSHash: "281b59ca621d35d254abbddc1f088870ed61cb28", CSSHash: "7cae98eaf8e3d5d1cd7fadaa6806ce3d65d74d92"}},
"Astro.Mechanism.CharacterCloud.create": {Name: "Astro.Mechanism.CharacterCloud.create", Kind: "method", Parent: "Astro.Mechanism.CharacterCloud", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
"Astro.Mechanism.Parallax": {Name: "Astro.Mechanism.Parallax", Kind: "class", Parent: "Astro.Mechanism", Imports: []string{"System.Cycle", "Dandelion", "Dandelion.IDOMObject"}, Resource: classmap.Resource{Src: "Astro/Mechanism/Parallax.js", JSHash: "ba7b1816fc5d32edfaf5b93b9d35c7b2c297f011", CSSHash: "f8c02f4ec1be082e02c51f0b5ea39cbdd5b0e49f"}},
"Astro.Mechanism.Parallax": {Name: "Astro.Mechanism.Parallax", Kind: "class", Parent: "Astro.Mechanism", Imports: []string{"System.Cycle", "Dandelion", "Dandelion.IDOMObject"}, Resource: classmap.Resource{Src: "Astro/Mechanism/Parallax.js", JSHash: "6ac80e95f9e8ba391668e1988fe3586987ea79d0", CSSHash: "f8c02f4ec1be082e02c51f0b5ea39cbdd5b0e49f"}},
"Astro.Mechanism.Parallax.attach": {Name: "Astro.Mechanism.Parallax.attach", Kind: "method", Parent: "Astro.Mechanism.Parallax", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
"Astro.Mechanism.Parallax.cssSlide": {Name: "Astro.Mechanism.Parallax.cssSlide", Kind: "method", Parent: "Astro.Mechanism.Parallax", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
"Astro.Mechanism.Parallax.verticalSlideTo": {Name: "Astro.Mechanism.Parallax.verticalSlideTo", Kind: "method", Parent: "Astro.Mechanism.Parallax", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
@@ -117,7 +117,7 @@ var ClassMap = &classmap.Map{
"Astro.utils.Date.prettyDay": {Name: "Astro.utils.Date.prettyDay", Kind: "method", Parent: "Astro.utils.Date", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
"Astro.utils.Date.smstamp": {Name: "Astro.utils.Date.smstamp", Kind: "method", Parent: "Astro.utils.Date", Imports: []string(nil), Resource: classmap.Resource{Src: "", JSHash: "", CSSHash: ""}},
"Components": {Name: "Components", Kind: "class", Parent: "", Imports: []string(nil), Resource: classmap.Resource{Src: "Components/_this.js", JSHash: "f4cb7babe62a5cdae34d2c4ebcb55071e81da4ff", CSSHash: "1"}},
"Components.Console": {Name: "Components.Console", Kind: "class", Parent: "Components", Imports: []string{"System.utils.Perf", "System.Cycle", "System.Cycle.TICK", "System.Global", "System.Log", "System.Debug", "Dandelion", "Dandelion.IDOMElement", "Components.DockPanel"}, Resource: classmap.Resource{Src: "Components/Console.js", JSHash: "115be15db72bd22f8222510e7bf4ce0c741028fb", CSSHash: "452f4a36e8fd7321c7d177a311047c8b71165e48"}},
"Components.Console": {Name: "Components.Console", Kind: "class", Parent: "Components", Imports: []string{"System.utils.Perf", "System.Cycle", "System.Cycle.TICK", "System.Global", "System.Log", "System.Debug", "Dandelion", "Dandelion.IDOMElement", "Components.DockPanel"}, Resource: classmap.Resource{Src: "Components/Console.js", JSHash: "9e4ba7f921f39c85f264e416669134120d4668ea", CSSHash: "452f4a36e8fd7321c7d177a311047c8b71165e48"}},
"Components.DockPanel": {Name: "Components.DockPanel", Kind: "class", Parent: "Components", Imports: []string{"System.Cycle", "System.utils.DataKey", "Dandelion", "Dandelion.IDOMElement"}, Resource: classmap.Resource{Src: "Components/DockPanel.js", JSHash: "c74b3081efdcbfa13300e9a49529f5664734b24e", CSSHash: "af0d91982c764ee62c46b243be68c08f2808e82b"}},
"Components.MessageBox": {Name: "Components.MessageBox", Kind: "class", Parent: "Components", Imports: []string{"System.Cycle.Trigger", "Dandelion", "Dandelion.IDOMObject", "System.utils.EventKey", "Dandelion.CSSAnimations"}, Resource: classmap.Resource{Src: "Components/MessageBox.js", JSHash: "db0b55a5e0b1a92b9781c2b0b13817355b8e3cdf", CSSHash: "5571fa4c2e1324dcf1f2e18df8b6105cf37dfc53"}},
"Components.Mouse": {Name: "Components.Mouse", Kind: "class", Parent: "Components", Imports: []string(nil), Resource: classmap.Resource{Src: "Components/Mouse/_this.js", JSHash: "9ec5ced53a20ea1d057e2142668e27e5df7d49f6", CSSHash: "1"}},
@@ -379,8 +379,8 @@ var ClassMap = &classmap.Map{
"Astro/Blog/SharedStyle.js": {Src: "Astro/Blog/SharedStyle.js", JSHash: "e946130da823a5b2d089b5b416c13b628eb1637d", CSSHash: "f8ff15304a5e38e199b713bac48e282d2bf10f45"},
"Astro/Bootstrap.js": {Src: "Astro/Bootstrap.js", JSHash: "51bfb270eadd20b4b71372ae2d20dcf3d20575db", CSSHash: "e650f4de36f799af80ca0633d66351fb9333d620"},
"Astro/Common/Element/Footer.js": {Src: "Astro/Common/Element/Footer.js", JSHash: "80f69d85c399bdc04d3b2055d1ebbe9ee77a852a", CSSHash: "c26f4238a6a4f2fc0bcbd9ac86141d12522552a4"},
"Astro/Mechanism/CharacterCloud.js": {Src: "Astro/Mechanism/CharacterCloud.js", JSHash: "540a2085798928418a54e10d56bc037863ee57a9", CSSHash: "7cae98eaf8e3d5d1cd7fadaa6806ce3d65d74d92"},
"Astro/Mechanism/Parallax.js": {Src: "Astro/Mechanism/Parallax.js", JSHash: "ba7b1816fc5d32edfaf5b93b9d35c7b2c297f011", CSSHash: "f8c02f4ec1be082e02c51f0b5ea39cbdd5b0e49f"},
"Astro/Mechanism/CharacterCloud.js": {Src: "Astro/Mechanism/CharacterCloud.js", JSHash: "281b59ca621d35d254abbddc1f088870ed61cb28", CSSHash: "7cae98eaf8e3d5d1cd7fadaa6806ce3d65d74d92"},
"Astro/Mechanism/Parallax.js": {Src: "Astro/Mechanism/Parallax.js", JSHash: "6ac80e95f9e8ba391668e1988fe3586987ea79d0", CSSHash: "f8c02f4ec1be082e02c51f0b5ea39cbdd5b0e49f"},
"Astro/Penguin/Layout/MainFrame.js": {Src: "Astro/Penguin/Layout/MainFrame.js", JSHash: "b2f58fc9394745c1e47dfb95c4043f59f76acc1a", CSSHash: "e87b69ab9e725e4801065850790670d76f0a6d18"},
"Astro/Penguin/Page/Docs.js": {Src: "Astro/Penguin/Page/Docs.js", JSHash: "02217e7fa4ebffe90b32002ef07da500ac02bf52", CSSHash: "5230a026499b9ab0f4f530f4975a9df89170c83b"},
"Astro/Penguin/Page/_this.js": {Src: "Astro/Penguin/Page/_this.js", JSHash: "66e415e546eb6ca0b84cedfd4d3b6de67c2164f3", CSSHash: "e8afcaa8c75b241cd933cfc99a648adc42f815d7"},
@@ -393,7 +393,7 @@ var ClassMap = &classmap.Map{
"Astro/Starfall/_this.js": {Src: "Astro/Starfall/_this.js", JSHash: "77ca61d1ba806c3440cec5e26a100581259e1784", CSSHash: "1"},
"Astro/utils/Date.js": {Src: "Astro/utils/Date.js", JSHash: "45221fe447d15fd943310fe9d3d3308f884b6aec", CSSHash: "1"},
"Astro/utils/_this.js": {Src: "Astro/utils/_this.js", JSHash: "21e99449ec5c1a4b6d25164db9434132aeea5ad3", CSSHash: "1"},
"Components/Console.js": {Src: "Components/Console.js", JSHash: "115be15db72bd22f8222510e7bf4ce0c741028fb", CSSHash: "452f4a36e8fd7321c7d177a311047c8b71165e48"},
"Components/Console.js": {Src: "Components/Console.js", JSHash: "9e4ba7f921f39c85f264e416669134120d4668ea", CSSHash: "452f4a36e8fd7321c7d177a311047c8b71165e48"},
"Components/DockPanel.js": {Src: "Components/DockPanel.js", JSHash: "c74b3081efdcbfa13300e9a49529f5664734b24e", CSSHash: "af0d91982c764ee62c46b243be68c08f2808e82b"},
"Components/MessageBox.js": {Src: "Components/MessageBox.js", JSHash: "db0b55a5e0b1a92b9781c2b0b13817355b8e3cdf", CSSHash: "5571fa4c2e1324dcf1f2e18df8b6105cf37dfc53"},
"Components/Mouse/Clipboard.js": {Src: "Components/Mouse/Clipboard.js", JSHash: "574a1ef17878beb21395a2eecfa75d046ff694e0", CSSHash: "1b7f85206ce1560ed23d3b270e093022e25d2e61"},
@@ -0,0 +1,108 @@
// Code generated by externs-gen; DO NOT EDIT.
package generated
var Externs = []string{
"externs/Astro.Blog.AstroEdit.Article.js",
"externs/Astro.Blog.AstroEdit.IPlugin.js",
"externs/Astro.Blog.AstroEdit.SmartInput.Definition.js",
"externs/Astro.Blog.AstroEdit.SmartInput.ICandidateAction.js",
"externs/Astro.Blog.AstroEdit.SmartInput.js",
"externs/Astro.Blog.AstroEdit.Visualizer.Snippet.Model.js",
"externs/Astro.Blog.AstroEdit.Visualizer.Snippet.js",
"externs/Astro.Blog.AstroEdit.Visualizer.js",
"externs/Astro.Blog.AstroEdit.js",
"externs/Astro.Blog.Components.Bubble.js",
"externs/Astro.Blog.Components.Calendar.js",
"externs/Astro.Blog.Components.SiteFile.js",
"externs/Astro.Blog.Components.js",
"externs/Astro.Blog.Config.js",
"externs/Astro.Blog.Events.Responsive.js",
"externs/Astro.Blog.Events.js",
"externs/Astro.Blog.js",
"externs/Astro.Bootstrap.js",
"externs/Astro.Mechanism.CharacterCloud.js",
"externs/Astro.Mechanism.Parallax.js",
"externs/Astro.Mechanism.js",
"externs/Astro.js",
"externs/Astro.utils.Date.js",
"externs/Astro.utils.js",
"externs/BotanEvent.js",
"externs/BotanJS.js",
"externs/Components.MessageBox.js",
"externs/Components.Mouse.Clipboard.js",
"externs/Components.Mouse.ContextMenu.js",
"externs/Components.Mouse.js",
"externs/Components.Vim.Actions.js",
"externs/Components.Vim.Controls.ActionEvent.js",
"externs/Components.Vim.Controls.js",
"externs/Components.Vim.Cursor.js",
"externs/Components.Vim.DateTime.js",
"externs/Components.Vim.IAction.js",
"externs/Components.Vim.LineBuffer.js",
"externs/Components.Vim.LineFeeder.js",
"externs/Components.Vim.State.History.js",
"externs/Components.Vim.State.Marks.js",
"externs/Components.Vim.State.Recorder.js",
"externs/Components.Vim.State.Registers.js",
"externs/Components.Vim.State.Stack.js",
"externs/Components.Vim.State.js",
"externs/Components.Vim.StatusBar.js",
"externs/Components.Vim.Syntax.Analyzer.js",
"externs/Components.Vim.Syntax.TokenMatch.js",
"externs/Components.Vim.Syntax.Word.js",
"externs/Components.Vim.Syntax.js",
"externs/Components.Vim.VimArea.js",
"externs/Components.Vim.js",
"externs/Components.js",
"externs/Dandelion.CSSAnimations.MovieClip.js",
"externs/Dandelion.CSSAnimations.js",
"externs/Dandelion.IDOMElement.js",
"externs/Dandelion.IDOMObject.js",
"externs/Dandelion.js",
"externs/Libraries.SyntaxHighLighter.Brush.js",
"externs/Libraries.SyntaxHighLighter.js",
"externs/Libraries.js",
"externs/System.Compression.Zlib.js",
"externs/System.Compression.js",
"externs/System.Cycle.Trigger.js",
"externs/System.Cycle.js",
"externs/System.Debug.js",
"externs/System.Encoding.Base64.js",
"externs/System.Encoding.Utf8.js",
"externs/System.Encoding.js",
"externs/System.Global.js",
"externs/System.Log.js",
"externs/System.Net.js",
"externs/System.Policy.js",
"externs/System.Tick.js",
"externs/System.js",
"externs/System.utils.DataKey.js",
"externs/System.utils.EventKey.js",
"externs/System.utils.IKey.js",
"externs/System.utils.Perf.js",
"externs/System.utils.js",
"externs/_3rdParty_.Recaptcha.js",
"externs/_3rdParty_.js",
"externs/_AstConf_.Article.js",
"externs/_AstConf_.AstroEdit.js",
"externs/_AstConf_.Comment.js",
"externs/_AstConf_.Control.js",
"externs/_AstConf_.Login.js",
"externs/_AstConf_.Notification.js",
"externs/_AstConf_.SiteFile.js",
"externs/_AstConf_.UserInfo.js",
"externs/_AstConf_.js",
"externs/_AstJson_.AJaxGetArticle.js",
"externs/_AstJson_.AJaxGetDrafts.js",
"externs/_AstJson_.AJaxGetFiles.Request.js",
"externs/_AstJson_.AJaxGetFiles.js",
"externs/_AstJson_.AJaxGetNotis.js",
"externs/_AstJson_.SiteFile.js",
"externs/_AstJson_.js",
"externs/_AstXObject_.AstroEdit.Visualizer.Snippet.Code.js",
"externs/_AstXObject_.AstroEdit.Visualizer.Snippet.Spoiler.js",
"externs/_AstXObject_.AstroEdit.Visualizer.Snippet.js",
"externs/_AstXObject_.AstroEdit.Visualizer.js",
"externs/_AstXObject_.AstroEdit.js",
"externs/_AstXObject_.js",
}
+60 -2
View File
@@ -14,8 +14,10 @@ import (
"regexp"
"sort"
"strings"
"sync"
"github.com/tgckpg/botanres-go/internal/classmap"
"github.com/tgckpg/resolver-go/internal/classmap"
"github.com/tgckpg/resolver-go/internal/closure"
)
type OutputMode string
@@ -38,6 +40,9 @@ type Result struct {
type Resolver struct {
Root string
Map *classmap.Map
externMu sync.RWMutex
externCache map[string]closure.SourceInput
}
func New(root string, m *classmap.Map) (*Resolver, error) {
@@ -45,7 +50,11 @@ func New(root string, m *classmap.Map) (*Resolver, error) {
if err != nil {
return nil, err
}
return &Resolver{Root: root, Map: m}, nil
return &Resolver{
Root: root,
Map: m,
externCache: make(map[string]closure.SourceInput),
}, nil
}
func (r *Resolver) ResolveRequest(code string, mode OutputMode, excludes []string) (Result, error) {
@@ -242,6 +251,55 @@ func (r *Resolver) MergeCSS(files []classmap.Resource) ([]byte, string, error) {
return b.Bytes(), hashList(files, "css"), nil
}
func (r *Resolver) GetExterns(files []string) ([]closure.SourceInput, error) {
sources := make([]closure.SourceInput, 0, len(files))
for _, f := range files {
src, ok, err := r.getExtern(f)
if err != nil {
return nil, err
}
if !ok {
continue
}
sources = append(sources, src)
}
return sources, nil
}
func (r *Resolver) getExtern(f string) (closure.SourceInput, bool, error) {
// Fast path: read cache.
r.externMu.RLock()
src, ok := r.externCache[f]
r.externMu.RUnlock()
if ok {
return src, true, nil
}
// Slow path: read file.
b, err := os.ReadFile(filepath.Join(r.Root, filepath.FromSlash(f)))
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return closure.SourceInput{}, false, nil
}
return closure.SourceInput{}, false, err
}
src = closure.SourceInput{
Name: f,
Source: string(b),
}
// Store cache.
r.externMu.Lock()
r.externCache[f] = src
r.externMu.Unlock()
return src, true, nil
}
func DecodeRequest(code string) ([]string, error) {
sep := "/"
decoded := code