mirror of
https://github.com/studiokaiji/nostr-webhost.git
synced 2025-12-17 06:44:28 +01:00
Merge pull request #57 from studiokaiji/feature-#46-nip95-file-upload
Feature #46 nip95 file upload
This commit is contained in:
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,8 +64,13 @@ func Start(port string, mode string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filter := nostr.Filter{
|
filter := nostr.Filter{
|
||||||
Kinds: []int{consts.KindWebhostHTML, consts.KindWebhostCSS, consts.KindWebhostJS, consts.KindWebhostPicture},
|
Kinds: []int{
|
||||||
IDs: ids,
|
consts.KindWebhostHTML,
|
||||||
|
consts.KindWebhostCSS,
|
||||||
|
consts.KindWebhostJS,
|
||||||
|
consts.KindTextFile,
|
||||||
|
},
|
||||||
|
IDs: ids,
|
||||||
}
|
}
|
||||||
if mode == "secure" {
|
if mode == "secure" {
|
||||||
filter.Authors = []string{subdomainPubKey}
|
filter.Authors = []string{subdomainPubKey}
|
||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
hostr/cmd/tools/getResponseContent.go
Normal file
14
hostr/cmd/tools/getResponseContent.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user