Skip to content

Commit

Permalink
Merge pull request #56 from studiokaiji/feature-#46-nip95-file-upload
Browse files Browse the repository at this point in the history
Feature #46 nip95 file upload
  • Loading branch information
studiokaiji authored Nov 9, 2023
2 parents 7e9b0df + 421b1c5 commit c608573
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 115 deletions.
3 changes: 3 additions & 0 deletions example/public/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "test"
}
47 changes: 17 additions & 30 deletions hostr/cmd/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/studiokaiji/nostr-webhost/hostr/cmd/consts"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/keystore"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/relays"
"golang.org/x/exp/slices"
"golang.org/x/net/html"
)

Expand Down Expand Up @@ -73,6 +72,19 @@ func Deploy(basePath string, replaceable bool, htmlIdentifier string) (string, s
return "", "", "", err
}

// basePath以下のText Fileのパスをすべて羅列する
err = generateEventsAndAddQueueAllValidStaticTextFiles(
priKey,
pubKey,
htmlIdentifier,
basePath,
replaceable,
)
if err != nil {
fmt.Println("❌ Failed to convert text files:", err)
return "", "", "", err
}

// basePath以下のMedia Fileのパスを全て羅列しアップロード
err = uploadAllValidStaticMediaFiles(priKey, pubKey, basePath)
if err != nil {
Expand Down Expand Up @@ -107,8 +119,8 @@ func Deploy(basePath string, replaceable bool, htmlIdentifier string) (string, s
fmt.Println("❌ Failed to get public key:", err)
return "", "", "", err
}
addNostrEventQueue(event)
fmt.Println("Added", filePath, "event to publish queue")

addNostrEventQueue(event, filePath)

eventId, encoded := publishEventsFromQueue(replaceable)

Expand Down Expand Up @@ -157,7 +169,7 @@ func convertLinks(
// jsファイルを解析する
if strings.HasSuffix(a.Val, ".js") {
// アップロード済みファイルの元パスとURLを取得
for path, url := range uploadedMediaFiles {
for path, url := range uploadedMediaFilePathToURL {
// JS内に該当ファイルがあったら置換
content = strings.ReplaceAll(content, path, url)
}
Expand All @@ -169,8 +181,7 @@ func convertLinks(
break
}

addNostrEventQueue(event)
fmt.Println("Added", filePath, "event to publish queue")
addNostrEventQueue(event, filePath)

// 置き換え可能なイベントでない場合
if !replaceable {
Expand All @@ -184,26 +195,6 @@ func convertLinks(
}
}
}
} else if slices.Contains(availableMediaHtmlTags, n.Data) {
// 内部mediaファイルを対象にUpload Requestを作成
for _, a := range n.Attr {
if (a.Key == "href" || a.Key == "src" || a.Key == "data") && !isExternalURL(a.Val) && isValidMediaFileType(a.Val) {
filePath := filepath.Join(basePath, a.Val)

// contentを取得
bytesContent, err := os.ReadFile(filePath)
if err != nil {
fmt.Println("❌ Failed to read", filePath, ":", err)
continue
}

content := string(bytesContent)

if url, ok := uploadedMediaFiles[filePath]; ok {
content = strings.ReplaceAll(content, filePath, url)
}
}
}
}
}

Expand All @@ -212,7 +203,3 @@ func convertLinks(
convertLinks(priKey, pubKey, basePath, replaceable, indexHtmlIdentifier, c)
}
}

func convertLinksFromJS() {

}
83 changes: 8 additions & 75 deletions hostr/cmd/deploy/media.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,13 @@ import (
"mime/multipart"
"net/http"
"os"
"path/filepath"
"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",
Expand All @@ -49,24 +32,6 @@ var availableContentSuffixes = []string{
".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 {
Expand All @@ -82,21 +47,21 @@ type MediaResult struct {
}

// [元パス]:[URL]の形で記録する
var uploadedMediaFiles = map[string]string{}
var uploadedMediaFilePathToURL = map[string]string{}

func uploadMediaFiles(filePaths []string, requests []*http.Request) {
fmt.Println("Uploading media files...")

client := &http.Client{}

var uploadedMediaFilesCount = 0
var uploadedMediaFilePathToURLCount = 0
var allMediaFilesCount = len(requests)

var wg sync.WaitGroup

go func() {
wg.Add(1)
tools.DisplayProgressBar(&uploadedMediaFilesCount, &allMediaFilesCount)
tools.DisplayProgressBar(&uploadedMediaFilePathToURLCount, &allMediaFilesCount)
wg.Done()
}()

Expand Down Expand Up @@ -140,9 +105,9 @@ func uploadMediaFiles(filePaths []string, requests []*http.Request) {
return
}

mutex.Lock() // ロックして排他制御
uploadedMediaFilesCount++ // カウントアップ
uploadedMediaFiles[filePath] = result.Url
mutex.Lock() // ロックして排他制御
uploadedMediaFilePathToURLCount++ // カウントアップ
uploadedMediaFilePathToURL[filePath] = result.Url
mutex.Unlock() // ロック解除
}(filePath, req)
}
Expand All @@ -152,7 +117,7 @@ func uploadMediaFiles(filePaths []string, requests []*http.Request) {

func filePathToUploadMediaRequest(basePath, filePath, priKey, pubKey string) (*http.Request, error) {
// ファイルを開く
file, err := os.Open(filepath.Join(basePath, filePath))
file, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("Failed to read %s: %w", filePath, err)
}
Expand Down Expand Up @@ -221,39 +186,7 @@ func filePathToUploadMediaRequest(basePath, filePath, priKey, pubKey string) (*h

// basePath以下のMedia Fileのパスを全て羅列する
func listAllValidStaticMediaFilePaths(basePath string) ([]string, error) {
mediaFilePaths := []string{}

err := filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

// ディレクトリはスキップ
if !info.IsDir() {
// 各サフィックスに対してマッチングを試みる
for _, suffix := range availableContentSuffixes {
// ファイル名とサフィックスがマッチした場合
if strings.HasSuffix(strings.ToLower(info.Name()), strings.ToLower(suffix)) {
// フルパスからbasePathまでの相対パスを計算
relPath, err := filepath.Rel(basePath, path)
if err != nil {
fmt.Println("❌ Error calculating relative path:", err)
continue
}
// マッチするファイルの相対パスをスライスに追加
mediaFilePaths = append(mediaFilePaths, "/"+relPath)
break
}
}
}
return nil
})

if err != nil {
return nil, err
}

return mediaFilePaths, nil
return tools.FindFilesWithBasePathBySuffixes(basePath, availableContentSuffixes)
}

// basePath以下のMedia Fileのパスを全て羅列しアップロード
Expand Down
19 changes: 10 additions & 9 deletions hostr/cmd/deploy/nostr.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ func publishEventsFromQueue(replaceable bool) (string, string) {

// Publishの進捗状況を表示
allEventsCount := len(nostrEventsQueue)
uploadedMediaFilesCount := 0
uploadedMediaFilePathToURLCount := 0

var wg sync.WaitGroup

go func() {
wg.Add(1)
tools.DisplayProgressBar(&uploadedMediaFilesCount, &allEventsCount)
tools.DisplayProgressBar(&uploadedMediaFilePathToURLCount, &allEventsCount)
wg.Done()
}()

Expand All @@ -76,17 +76,17 @@ func publishEventsFromQueue(replaceable bool) (string, string) {
continue
}
}
mutex.Lock() // ロックして排他制御
uploadedMediaFilesCount++ // カウントアップ
mutex.Unlock() // ロック解除
wg.Done() // ゴルーチンの終了を通知
mutex.Lock() // ロックして排他制御
uploadedMediaFilePathToURLCount++ // カウントアップ
mutex.Unlock() // ロック解除
wg.Done() // ゴルーチンの終了を通知
}(ev)
}

wg.Wait()

if uploadedMediaFilesCount < allEventsCount {
fmt.Println("Failed to deploy", allEventsCount-uploadedMediaFilesCount, "files.")
if uploadedMediaFilePathToURLCount < allEventsCount {
fmt.Println("Failed to deploy", allEventsCount-uploadedMediaFilePathToURLCount, "files.")
}

indexEvent := nostrEventsQueue[len(nostrEventsQueue)-1]
Expand Down Expand Up @@ -140,6 +140,7 @@ func getReplaceableIdentifier(indexHtmlIdentifier, filePath string) string {

var nostrEventsQueue []*nostr.Event

func addNostrEventQueue(event *nostr.Event) {
func addNostrEventQueue(event *nostr.Event, filePath string) {
nostrEventsQueue = append(nostrEventsQueue, event)
fmt.Println("Added", filePath, "event to publish queue")
}
90 changes: 90 additions & 0 deletions hostr/cmd/deploy/textFile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package deploy

import (
"encoding/base64"
"os"
"path/filepath"

"github.com/nbd-wtf/go-nostr"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/tools"
)

// 有効なText Fileの拡張子
var availableTextFileSuffixes = []string{
".txt",
".csv",
".pdf",
".json",
".yml",
".yaml",
".svg",
}

// [Text Fileの拡張子]: Content-Typeで記録する
var availableTextFileContentTypes = map[string]string{
".txt": "text/plain",
".csv": "text/csv",
".pdf": "application/pdf",
".json": "application/json",
".yml": "application/x-yaml",
".yaml": "application/x-yaml",
".svg": "image/svg+xml",
}

// [元パス]:[event]の形で記録する
var textFilePathToEvent = map[string]*nostr.Event{}

// basePath以下のText Fileのパスを全て羅列する
func listAllValidStaticTextFiles(basePath string) ([]string, error) {
return tools.FindFilesWithBasePathBySuffixes(basePath, availableTextFileSuffixes)
}

// Text fileをBase pathから割り出して、eventを生成しキューに追加
func generateEventsAndAddQueueAllValidStaticTextFiles(priKey, pubKey, indexHtmlIdentifier, basePath string, replaceable bool) error {
filePaths, err := listAllValidStaticTextFiles(basePath)
if err != nil {
return err
}

for _, filePath := range filePaths {
// ファイルを開く
bytesContent, err := os.ReadFile(filePath)
if err != nil {
return err
}

// ファイル内容をbase64エンコード
content := base64.StdEncoding.EncodeToString(bytesContent)

tags := nostr.Tags{}
// 置き換え可能なイベントの場合
if replaceable {
fileIdentifier := getReplaceableIdentifier(indexHtmlIdentifier, filePath)
tags = tags.AppendUnique(nostr.Tag{"d", fileIdentifier})
}

// 拡張子からContent-Typeを取得
contentType := availableTextFileContentTypes[filepath.Ext(filePath)]
tags = tags.AppendUnique(nostr.Tag{"type", contentType})

// kindを設定
var kind int
if replaceable {
kind = 30064
} else {
kind = 1064
}

// eventを取得
event, err := getEvent(priKey, pubKey, content, kind, tags)
if err != nil {
return err
}

textFilePathToEvent[filePath] = event

addNostrEventQueue(event, filePath)
}

return nil
}
Loading

0 comments on commit c608573

Please sign in to comment.