Merge pull request #57 from studiokaiji/feature-#46-nip95-file-upload

Feature #46 nip95 file upload
This commit is contained in:
kaiji
2023-11-10 16:24:25 +09:00
committed by GitHub
7 changed files with 92 additions and 19 deletions

View File

@@ -5,7 +5,9 @@ const (
KindWebhostHTML = 5392 KindWebhostHTML = 5392
KindWebhostCSS = 5393 KindWebhostCSS = 5393
KindWebhostJS = 5394 KindWebhostJS = 5394
KindTextFile = 1064
KindWebhostReplaceableHTML = 35392 KindWebhostReplaceableHTML = 35392
KindWebhostReplaceableCSS = 35393 KindWebhostReplaceableCSS = 35393
KindWebhostReplaceableJS = 35394 KindWebhostReplaceableJS = 35394
KindReplaceableTextFile = 30064
) )

View File

@@ -49,7 +49,7 @@ type MediaResult struct {
// [元パス]:[URL]の形で記録する // [元パス]:[URL]の形で記録する
var uploadedMediaFilePathToURL = map[string]string{} var uploadedMediaFilePathToURL = map[string]string{}
func uploadMediaFiles(filePaths []string, requests []*http.Request) { func uploadMediaFiles(basePath string, filePaths []string, requests []*http.Request) {
fmt.Println("Uploading media files...") fmt.Println("Uploading media files...")
client := &http.Client{} client := &http.Client{}
@@ -72,7 +72,7 @@ func uploadMediaFiles(filePaths []string, requests []*http.Request) {
wg.Add(1) wg.Add(1)
filePath := filePaths[i] filePath := filePaths[i]
fmt.Printf("\nAdded upload request %s", filePath) fmt.Println("Added upload request", filePath)
go func(filePath string, req *http.Request) { go func(filePath string, req *http.Request) {
defer wg.Done() defer wg.Done()
@@ -107,7 +107,7 @@ func uploadMediaFiles(filePaths []string, requests []*http.Request) {
mutex.Lock() // ロックして排他制御 mutex.Lock() // ロックして排他制御
uploadedMediaFilePathToURLCount++ // カウントアップ uploadedMediaFilePathToURLCount++ // カウントアップ
uploadedMediaFilePathToURL[filePath] = result.Url uploadedMediaFilePathToURL[strings.Replace(filePath, basePath, "", 1)] = result.Url
mutex.Unlock() // ロック解除 mutex.Unlock() // ロック解除
}(filePath, req) }(filePath, req)
} }
@@ -206,7 +206,7 @@ func uploadAllValidStaticMediaFiles(priKey, pubKey, basePath string) error {
requests = append(requests, request) requests = append(requests, request)
} }
uploadMediaFiles(filesPaths, requests) uploadMediaFiles(basePath, filesPaths, requests)
return nil return nil
} }

View File

@@ -4,6 +4,7 @@ import (
"encoding/base64" "encoding/base64"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/tools" "github.com/studiokaiji/nostr-webhost/hostr/cmd/tools"
@@ -59,7 +60,11 @@ func generateEventsAndAddQueueAllValidStaticTextFiles(priKey, pubKey, indexHtmlI
tags := nostr.Tags{} tags := nostr.Tags{}
// 置き換え可能なイベントの場合 // 置き換え可能なイベントの場合
if replaceable { if replaceable {
fileIdentifier := getReplaceableIdentifier(indexHtmlIdentifier, filePath) // filePathからbasePathを取り除く
pathForIdentifier := strings.Replace(filePath, basePath, "", 1)
// 識別子を取得
fileIdentifier := getReplaceableIdentifier(indexHtmlIdentifier, pathForIdentifier)
tags = tags.AppendUnique(nostr.Tag{"d", fileIdentifier}) tags = tags.AppendUnique(nostr.Tag{"d", fileIdentifier})
} }

View File

@@ -64,7 +64,12 @@ func Start(port string, mode string) {
} }
filter := nostr.Filter{ filter := nostr.Filter{
Kinds: []int{consts.KindWebhostHTML, consts.KindWebhostCSS, consts.KindWebhostJS, consts.KindWebhostPicture}, Kinds: []int{
consts.KindWebhostHTML,
consts.KindWebhostCSS,
consts.KindWebhostJS,
consts.KindTextFile,
},
IDs: ids, IDs: ids,
} }
if mode == "secure" { if mode == "secure" {
@@ -74,11 +79,16 @@ func Start(port string, mode string) {
// Poolからデータを取得する // Poolからデータを取得する
ev := pool.QuerySingle(ctx, allRelays, filter) ev := pool.QuerySingle(ctx, allRelays, filter)
if ev != nil { if ev != nil {
contentType, err := tools.GetContentType(ev.Kind) contentType, isTextFile, err := tools.GetContentType(ev)
if err != nil { if err != nil {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound)) ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
}
content, err := tools.GetResponseContent(ev.Content, isTextFile)
if err != nil {
ctx.String(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
} else { } else {
ctx.Data(http.StatusOK, contentType, []byte(ev.Content)) ctx.Data(http.StatusOK, contentType, content)
} }
} else { } else {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound)) ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
@@ -112,16 +122,24 @@ func Start(port string, mode string) {
consts.KindWebhostReplaceableHTML, consts.KindWebhostReplaceableHTML,
consts.KindWebhostReplaceableCSS, consts.KindWebhostReplaceableCSS,
consts.KindWebhostReplaceableJS, consts.KindWebhostReplaceableJS,
consts.KindReplaceableTextFile,
}, },
Authors: authors, Authors: authors,
Tags: tags, Tags: tags,
}) })
if ev != nil { if ev != nil {
contentType, err := tools.GetContentType(ev.Kind) contentType, isTextFile, err := tools.GetContentType(ev)
if err != nil { if err != nil {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound)) ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
} }
ctx.Data(http.StatusOK, contentType, []byte(ev.Content))
// contentの変換
content, err := tools.GetResponseContent(ev.Content, isTextFile)
if err != nil {
ctx.String(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
} else {
ctx.Data(http.StatusOK, contentType, content)
}
} else { } else {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound)) ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
} }
@@ -158,16 +176,24 @@ func Start(port string, mode string) {
consts.KindWebhostReplaceableHTML, consts.KindWebhostReplaceableHTML,
consts.KindWebhostReplaceableCSS, consts.KindWebhostReplaceableCSS,
consts.KindWebhostReplaceableJS, consts.KindWebhostReplaceableJS,
consts.KindReplaceableTextFile,
}, },
Authors: authors, Authors: authors,
Tags: tags, Tags: tags,
}) })
if ev != nil { if ev != nil {
contentType, err := tools.GetContentType(ev.Kind) contentType, isTextFile, err := tools.GetContentType(ev)
if err != nil { if err != nil {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound)) ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
} }
ctx.Data(http.StatusOK, contentType, []byte(ev.Content))
content, err := tools.GetResponseContent(ev.Content, isTextFile)
if err != nil {
ctx.String(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
} else {
ctx.Data(http.StatusOK, contentType, content)
}
} else { } else {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound)) ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
} }

View File

@@ -3,17 +3,32 @@ package tools
import ( import (
"fmt" "fmt"
"github.com/nbd-wtf/go-nostr"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/consts" "github.com/studiokaiji/nostr-webhost/hostr/cmd/consts"
) )
func GetContentType(kind int) (string, error) { // Content-Typeをイベントから取得する。NIP-95の場合は第二引数がtrueになる。
func GetContentType(event *nostr.Event) (string, bool, error) {
kind := event.Kind
if kind == consts.KindTextFile || kind == consts.KindReplaceableTextFile {
contentTypeTag := event.Tags.GetFirst([]string{"type"})
contentType := contentTypeTag.Value()
if len(contentType) < 1 {
return "", true, fmt.Errorf("Content-Type not specified")
}
return contentType, true, nil
}
if kind == consts.KindWebhostHTML || kind == consts.KindWebhostReplaceableHTML { if kind == consts.KindWebhostHTML || kind == consts.KindWebhostReplaceableHTML {
return "text/html; charset=utf-8", nil return "text/html; charset=utf-8", false, nil
} else if kind == consts.KindWebhostCSS || kind == consts.KindWebhostReplaceableCSS { } else if kind == consts.KindWebhostCSS || kind == consts.KindWebhostReplaceableCSS {
return "text/css; charset=utf-8", nil return "text/css; charset=utf-8", false, nil
} else if kind == consts.KindWebhostJS || kind == consts.KindWebhostReplaceableJS { } else if kind == consts.KindWebhostJS || kind == consts.KindWebhostReplaceableJS {
return "text/javascript; charset=utf-8", nil return "text/javascript; charset=utf-8", false, nil
} else { } else {
return "", fmt.Errorf("Invalid Kind") return "", false, fmt.Errorf("Invalid Kind")
} }
} }

View File

@@ -0,0 +1,14 @@
package tools
import (
"encoding/base64"
)
func GetResponseContent(eventContent string, isTextFile bool) ([]byte, error) {
if isTextFile {
// NIP-95ファイル(Text File)の場合はbase64エンコードされているのでdecodeする
return base64.StdEncoding.DecodeString(eventContent)
} else {
return []byte(eventContent), nil
}
}

View File

@@ -146,7 +146,18 @@ max_ws_frame_bytes = 1024000
#] #]
# Event kind allowlist. Events other than these kinds will be discarded. # Event kind allowlist. Events other than these kinds will be discarded.
event_kind_allowlist = [1964, 1965, 5392, 5393, 5394, 35392, 35393, 35394] event_kind_allowlist = [
1964,
1965,
5392,
5393,
5394,
30064,
30065,
35392,
35393,
35394,
]
[authorization] [authorization]
# Pubkey addresses in this array are whitelisted for event publishing. # Pubkey addresses in this array are whitelisted for event publishing.