From 79a51c6195d4a3245f6d7d8a6be6ad04f1b53de1 Mon Sep 17 00:00:00 2001 From: studiokaiji Date: Mon, 23 Oct 2023 12:57:36 +0900 Subject: [PATCH 1/8] Rename isValidFileType => isValidBasicFileType --- hostr/cmd/deploy/deploy.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hostr/cmd/deploy/deploy.go b/hostr/cmd/deploy/deploy.go index ff19deb..bbed854 100644 --- a/hostr/cmd/deploy/deploy.go +++ b/hostr/cmd/deploy/deploy.go @@ -137,7 +137,7 @@ func isExternalURL(urlStr string) bool { return err == nil && u.Scheme != "" && u.Host != "" } -func isValidFileType(str string) bool { +func isValidBasicFileType(str string) bool { return strings.HasSuffix(str, ".html") || strings.HasSuffix(str, ".css") || strings.HasSuffix(str, ".js") } @@ -230,7 +230,7 @@ func convertLinks(priKey, pubKey, basePath string, replaceable bool, indexHtmlId if n.Type == html.ElementNode && (n.Data == "link" || n.Data == "script") { for i, a := range n.Attr { // href,srcのうち、外部URLでないものかつ. html, .css, .js のみ変換する - if (a.Key == "href" || a.Key == "src") && !isExternalURL(a.Val) && isValidFileType(a.Val) { + if (a.Key == "href" || a.Key == "src") && !isExternalURL(a.Val) && isValidBasicFileType(a.Val) { filePath := filepath.Join(basePath, a.Val) // kindを取得 From f8d9658c6ce5baa6953cdc81ba2600e589d263bc Mon Sep 17 00:00:00 2001 From: studiokaiji Date: Tue, 24 Oct 2023 22:53:55 +0900 Subject: [PATCH 2/8] =?UTF-8?q?media=E3=81=AE=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=89=E6=A9=9F=E8=83=BD=E3=82=92=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hostr/cmd/deploy/media.go | 120 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 hostr/cmd/deploy/media.go diff --git a/hostr/cmd/deploy/media.go b/hostr/cmd/deploy/media.go new file mode 100644 index 0000000..b293f88 --- /dev/null +++ b/hostr/cmd/deploy/media.go @@ -0,0 +1,120 @@ +package deploy + +import ( + "fmt" + "strings" + "sync" + + "github.com/nbd-wtf/go-nostr" + "github.com/studiokaiji/nostr-webhost/hostr/cmd/tools" +) + +var availableContentTypes = []string{ + "image/png", + "image/jpg", + "image/jpeg", + "image/gif", + "image/webp", + "video/mp4", + "video/quicktime", + "video/mpeg", + "video/webm", + "audio/mpeg", + "audio/mpg", + "audio/mpeg3", + "audio/mp3", +} + +var availableContentSuffixes = []string{ + ".png", + ".jpg", + ".jpeg", + ".gif", + ".webp", + ".mp4", + ".quicktime", + ".mpeg", + ".webm", + ".mpeg", + ".mpg", + ".mpeg3", + ".mp3", +} + +var availableMediaHtmlTags = []string{ + "img", + "audio", + "video", + "source", + "object", + "embed", +} + +func isValidMediaFileType(path string) bool { + for _, suffix := range availableContentSuffixes { + if strings.HasSuffix(path, suffix) { + return true + } + } + return false +} + +const uploadEndpoint = "https://nostrcheck.me/api/v1/media" + +type MediaResult struct { + result bool + description string + status string + id int + pubkey string + url string + hash string + magnet string + tags []string +} + +var mediaUploadRequestQueue []func() (*MediaResult, error) + +func addNostrEventQueue(event *nostr.Event) { + nostrEventsQueue = append(nostrEventsQueue, event) +} + +func addMediaUploadRequestFuncQueue(reqFunc func() (*MediaResult, error)) { + mediaUploadRequestQueue = append(mediaUploadRequestQueue, reqFunc) +} + +var allRelays []string + +func uploadMediaFilesFromQueue() { + // Publishの進捗状況を表示 + allEventsCount := len(mediaUploadRequestQueue) + uploadedFilesCount := 0 + + var wg sync.WaitGroup + + go func() { + wg.Add(1) + tools.DisplayProgressBar(&uploadedFilesCount, &allEventsCount) + wg.Done() + }() + + var mutex sync.Mutex + + // アップロードを並列処理 + for _, reqFunc := range mediaUploadRequestQueue { + wg.Add(1) + go func(reqFun func() (*MediaResult, error)) { + _, err := reqFun() + if err != nil { + fmt.Println(err) + return + } + mutex.Lock() // ロックして排他制御 + uploadedFilesCount++ // カウントアップ + mutex.Unlock() // ロック解除 + wg.Done() // ゴルーチンの終了を通知 + }(reqFunc) + } + + wg.Wait() +} From a4ce10535ef6a9fa6ba690b33458076ffecf8155 Mon Sep 17 00:00:00 2001 From: studiokaiji Date: Tue, 24 Oct 2023 22:54:07 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Nostr=E7=89=B9=E6=9C=89=E3=81=AE=E3=83=AD?= =?UTF-8?q?=E3=82=B8=E3=83=83=E3=82=AF=E3=82=92=E5=88=86=E9=9B=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hostr/cmd/deploy/deploy.go | 354 ++++++++++++++++++------------------- hostr/cmd/deploy/nostr.go | 139 +++++++++++++++ 2 files changed, 312 insertions(+), 181 deletions(-) create mode 100644 hostr/cmd/deploy/nostr.go diff --git a/hostr/cmd/deploy/deploy.go b/hostr/cmd/deploy/deploy.go index bbed854..c3b96aa 100644 --- a/hostr/cmd/deploy/deploy.go +++ b/hostr/cmd/deploy/deploy.go @@ -3,144 +3,31 @@ package deploy import ( "bufio" "bytes" - "context" + "encoding/base64" + "encoding/json" "fmt" + "io" + "mime/multipart" + "net/http" "net/url" "os" "path/filepath" "strings" - "sync" "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip19" "github.com/studiokaiji/nostr-webhost/hostr/cmd/consts" "github.com/studiokaiji/nostr-webhost/hostr/cmd/keystore" "github.com/studiokaiji/nostr-webhost/hostr/cmd/relays" - "github.com/studiokaiji/nostr-webhost/hostr/cmd/tools" + "golang.org/x/exp/slices" "golang.org/x/net/html" ) -func pathToKind(path string, replaceable bool) (int, error) { - // パスを分割 - separatedPath := strings.Split(path, ".") - // 拡張子を取得 - ex := separatedPath[len(separatedPath)-1] - // replaceable(NIP-33)の場合はReplaceableなkindを返す - switch ex { - case "html": - if replaceable { - return consts.KindWebhostHTML, nil - } else { - return consts.KindWebhostReplaceableHTML, nil - } - case "css": - if replaceable { - return consts.KindWebhostReplaceableCSS, nil - } else { - return consts.KindWebhostCSS, nil - } - case "js": - if replaceable { - return consts.KindWebhostReplaceableJS, nil - } else { - return consts.KindWebhostJS, nil - } - default: - return 0, fmt.Errorf("Invalid path") - } -} - -// Replaceableにする場合のidentifier(dタグ)を取得 -func getReplaceableIdentifier(indexHtmlIdentifier, filePath string) string { - return indexHtmlIdentifier + "/" + filePath[1:] -} - -var nostrEventsQueue []*nostr.Event - -func addNostrEventQueue(event *nostr.Event) { - nostrEventsQueue = append(nostrEventsQueue, event) -} - -var allRelays []string - -func publishEventsFromQueue(replaceable bool) (string, string) { - ctx := context.Background() - - fmt.Println("Publishing...") - - // 各リレーに接続 - var relays []*nostr.Relay - - for _, url := range allRelays { - relay, err := nostr.RelayConnect(ctx, url) - if err != nil { - fmt.Println("❌ Failed to connect to:", url) - continue - } - relays = append(relays, relay) - } - - // Publishの進捗状況を表示 - allEventsCount := len(nostrEventsQueue) - uploadedFilesCount := 0 - - var wg sync.WaitGroup - - go func() { - wg.Add(1) - tools.DisplayProgressBar(&uploadedFilesCount, &allEventsCount) - wg.Done() - }() - - var mutex sync.Mutex - - // リレーへpublish - for _, ev := range nostrEventsQueue { - wg.Add(1) - go func(event *nostr.Event) { - for _, relay := range relays { - _, err := relay.Publish(ctx, *event) - if err != nil { - fmt.Println(err) - continue - } - } - mutex.Lock() // ロックして排他制御 - uploadedFilesCount++ // カウントアップ - mutex.Unlock() // ロック解除 - wg.Done() // ゴルーチンの終了を通知 - }(ev) - } - - wg.Wait() - - if uploadedFilesCount < allEventsCount { - fmt.Println("Failed to deploy", allEventsCount-uploadedFilesCount, "files.") - } - - indexEvent := nostrEventsQueue[len(nostrEventsQueue)-1] - - encoded := "" - if !replaceable { - if enc, err := nip19.EncodeEvent(indexEvent.ID, allRelays, indexEvent.PubKey); err == nil { - encoded = enc - } else { - fmt.Println("❌ Failed to covert nevent:", err) - } - } - - return indexEvent.ID, encoded -} - func isExternalURL(urlStr string) bool { u, err := url.Parse(urlStr) return err == nil && u.Scheme != "" && u.Host != "" } -func isValidBasicFileType(str string) bool { - return strings.HasSuffix(str, ".html") || strings.HasSuffix(str, ".css") || strings.HasSuffix(str, ".js") -} - func Deploy(basePath string, replaceable bool, htmlIdentifier string) (string, string, error) { // 引数からデプロイしたいサイトのパスを受け取る。 filePath := filepath.Join(basePath, "index.html") @@ -193,6 +80,13 @@ func Deploy(basePath string, replaceable bool, htmlIdentifier string) (string, s // リンクの解析と変換 convertLinks(priKey, pubKey, basePath, replaceable, htmlIdentifier, doc) + if len(mediaUploadRequestQueue) > 0 { + // メディアのアップロード + fmt.Println("📷 Uploading media files") + uploadMediaFilesFromQueue() + fmt.Println("📷 Media upload finished.") + } + // 更新されたHTML var buf bytes.Buffer html.Render(&buf, doc) @@ -226,55 +120,170 @@ func Deploy(basePath string, replaceable bool, htmlIdentifier string) (string, s } func convertLinks(priKey, pubKey, basePath string, replaceable bool, indexHtmlIdentifier string, n *html.Node) { - //