Skip to content

Commit

Permalink
feat: Support custom uploader
Browse files Browse the repository at this point in the history
  • Loading branch information
pluveto committed Feb 4, 2022
1 parent 7983f8a commit dbfe70e
Show file tree
Hide file tree
Showing 9 changed files with 447 additions and 66 deletions.
36 changes: 36 additions & 0 deletions extensions/smms.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"meta": {
"id": "smms",
"name": "SMMS Uploader",
"type": "simple-http-uploader",
"version": "0.0.1",
"repository": ""
},
"http": {
"request": {
"url": "https://sm.ms/api/v2/upload",
"method": "POST",
"headers": {
"Authorization": "#ext_config.token#",
"Content-Type": "multipart/form-data",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36"
},
"body": {
"format": {
"type": "string",
"value": "json"
},
"smfile": {
"type": "file",
"value": "#task.local_path#"
}
}
}
},
"upload": {
"rawUrl": {
"from": "json_response",
"path": "data.url"
}
}
}
57 changes: 21 additions & 36 deletions upload.go → github_upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,9 @@ type UploadOptions struct {
LocalPath string
}

type UploadStatus string

const (
Ignored UploadStatus = "ignored"
OK = "ok"
)

type UploadRet struct {
Status UploadStatus
TaskId int
LocalPath string
RawUrl string
Url string
Time time.Time
}

type GithubUploader struct {
Config GithubUploaderConfig
OnUploaded func(result Result[UploadRet])
OnUploaded func(result Result[*Task])
}

const kRawUrlFmt = "https://raw.githubusercontent.com/{username}/{repo}/{branch}/{path}"
Expand Down Expand Up @@ -76,10 +60,10 @@ func (u GithubUploader) PutFile(message, path, name string) (err error) {
return nil
}

func (u GithubUploader) Upload(taskId int, localPath, targetDir string) (ret Result[UploadRet]) {
func (u GithubUploader) Upload(taskId int, localPath, targetDir string) (ret Result[*Task]) {
now := time.Now()
base := filepath.Base(localPath)

// TODO: USE reference
var targetPath string
if len(targetDir) > 0 {
targetPath = targetDir + "/" + base
Expand All @@ -96,15 +80,15 @@ func (u GithubUploader) Upload(taskId int, localPath, targetDir string) (ret Res
} else {
GVerbose.Trace("failed to upload #TASK_%d %s : %s\n", taskId, localPath, err.Error())
}
ret = Result[UploadRet]{
ret = Result[*Task]{
err: err,
value: UploadRet{
Status: OK,
TaskId: taskId,
LocalPath: localPath,
RawUrl: rawUrl,
Url: url,
Time: now,
value: &Task{
Status: TASK_FINISHED,
TaskId: taskId,
LocalPath: localPath,
RawUrl: rawUrl,
Url: url,
FinishTime: now,
}}
return
}
Expand All @@ -124,17 +108,18 @@ func (u GithubUploader) buildUrl(urlfmt, path string) string {
func (u GithubUploader) UploadAll(localPaths []string, targetDir string) {
for taskId, localPath := range localPaths {

var ret Result[UploadRet]
var ret Result[*Task]
// ignore non-local path
if strings.HasPrefix(localPath, "http") {
ret = Result[UploadRet]{
value: UploadRet{
Status: Ignored,
TaskId: taskId,
LocalPath: localPath,
RawUrl: localPath,
Url: localPath,
Time: time.Now(),
ret = Result[*Task]{
value: &Task{
Ignored: true,
Status: TASK_FINISHED,
TaskId: taskId,
LocalPath: localPath,
RawUrl: localPath,
Url: localPath,
FinishTime: time.Now(),
},
}
} else {
Expand Down
6 changes: 0 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ github.com/alexflint/go-arg v1.4.2 h1:lDWZAXxpAnZUq4qwb86p/3rIJJ2Li81EoMbTMujhVa
github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM=
github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70=
github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -20,8 +17,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942 h1:t0lM6y/M5IiUZyvbBTcngso8SZEZICH7is9B6g/obVU=
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 h1:k/gmLsJDWwWqbLCur2yWnJzwQEKRcAHXo6seXGuSwWw=
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
golang.design/x/clipboard v0.6.0 h1:+U/e2KDBdpIjkRdxO8GwlD6dKD3Jx5zlNNzQjxte4A0=
golang.design/x/clipboard v0.6.0/go.mod h1:ep0pB+/4DGJK3ayLxweWJFHhHGGv3npJJHMXAjtLTUM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
Expand All @@ -44,7 +39,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
5 changes: 3 additions & 2 deletions lib/xmap/xmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func GetDeep[T any](m map[string]interface{}, path string) (ret T, err error) {
}

if path == "" {
ret = interface{}(m).(T)
return
}

Expand All @@ -35,9 +36,9 @@ func GetDeep[T any](m map[string]interface{}, path string) (ret T, err error) {
return v.(T), nil
}
} else {
err = errors.New("key not found")
err = errors.New("for path " + path + ", key " + key + " not found")
return
}
}
return
return interface{}(m).(T), nil
}
134 changes: 113 additions & 21 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/fs"
Expand All @@ -13,9 +15,10 @@ import (
"time"

"github.com/alexflint/go-arg"
"github.com/mitchellh/mapstructure"
"github.com/pelletier/go-toml/v2"
"github.com/pluveto/upgit/lib/xclipboard"
"github.com/mitchellh/mapstructure"
"github.com/pluveto/upgit/lib/xmap"
"golang.design/x/clipboard"
"gopkg.in/validator.v2"
)
Expand Down Expand Up @@ -80,9 +83,9 @@ func main() {
if opt.SizeLimit != nil && *opt.SizeLimit >= 0 {
maxUploadSize = *opt.SizeLimit
}
if !opt.NoLog {
if false == opt.NoLog {
GVerbose.LogEnabled = true
GVerbose.LogFile = MustApplicationPath("upgit.log")
GVerbose.LogFile = MustGetApplicationPath("upgit.log")
GVerbose.Info("Started")
}
GVerbose.VerboseEnabled = opt.Verbose
Expand Down Expand Up @@ -120,13 +123,13 @@ func main() {
return
}

func onUploaded(r Result[UploadRet]) {
func onUploaded(r Result[*Task]) {
if !r.Ok() && opt.OutputType == O_Stdout {
fmt.Println("Failed: " + r.err.Error())
GVerbose.Info("Failed to upload %s: %s", r.value.LocalPath, r.err.Error())
return
}
if opt.Clean && r.value.Status != Ignored {
if opt.Clean && !r.value.Ignored {
err := os.Remove(r.value.LocalPath)
if err != nil {
GVerbose.Info("Failed to remove %s: %s", r.value.LocalPath, err.Error())
Expand All @@ -135,19 +138,19 @@ func onUploaded(r Result[UploadRet]) {
}

}
outputLink(r.value)
recordHistory(r.value)
outputLink(*r.value)
recordHistory(*r.value)
}

func recordHistory(r UploadRet) {
os.WriteFile(MustApplicationPath("history.log"), []byte(
func recordHistory(r Task) {
os.WriteFile(MustGetApplicationPath("history.log"), []byte(
`{"time":"`+time.Now().Local().String()+`","rawUrl":"`+r.RawUrl+`","url":"`+r.Url+`"}`),
os.ModeAppend,
)
GVerbose.Info(MustMarshall(r))
}

func outputLink(r UploadRet) {
func outputLink(r Task) {
outContent, err := outputFormat(r)
abortErr(err)
switch opt.OutputType {
Expand All @@ -160,7 +163,7 @@ func outputLink(r UploadRet) {
}
}

func outputFormat(r UploadRet) (content string, err error) {
func outputFormat(r Task) (content string, err error) {
var outUrl string
if opt.Raw {
outUrl = r.RawUrl
Expand Down Expand Up @@ -240,31 +243,120 @@ func loadTomlConfig(cfg *Config) {

}

type Nullable[T any] struct {
Value *T
}

func loadUploaderConfig[T any](name string) (ret T, err error) {
var mCfg map[string]interface{}
bytes, err := ioutil.ReadFile(configFilePath)
if err != nil {
return
}
err = toml.Unmarshal(bytes, &mCfg)
if err != nil {
return
}
cfgMap := mCfg["uploaders"].(map[string]interface{})[name]
var cfg_ T
mapstructure.Decode(cfgMap, &cfg_)
ret = cfg_
return
}

func upload() {
if opt.Uploader == "" {
opt.Uploader = cfg.DefaultUploader
}
if opt.Uploader == "github" {
// load GithubUploader config
var mCfg map[string]interface{}
bytes, err := ioutil.ReadFile(configFilePath)
gCfg, err := loadUploaderConfig[GithubUploaderConfig](opt.Uploader)
abortErr(err)
abortErr(toml.Unmarshal(bytes, &mCfg))
gCfgMap := mCfg["uploaders"].(map[string]interface{})["github"]
var gCfg GithubUploaderConfig
mapstructure.Decode(gCfgMap, &gCfg)
if len(gCfg.Branch) == 0 {
gCfg.Branch = kDefaultBranch
}

uploader := GithubUploader{Config: gCfg, OnUploaded: onUploaded}
uploader.UploadAll(opt.LocalPaths, opt.TargetDir)
goto final
return
}

abortErr(errors.New("unknown uploader: " + opt.Uploader))
final:
// try http simple uploader
// list file in ./extensions
extDir := MustGetApplicationPath("extensions")
info, err := ioutil.ReadDir(extDir)
abortErr(err)
var uploader *SimpleHttpUploader
for _, f := range info {
fname := f.Name()
GVerbose.Trace("found file %s", fname)
if !strings.HasSuffix(fname, ".json") && !strings.HasSuffix(fname, ".jsonc") {
GVerbose.Trace("ignored file %s", fname)
continue
}
// load file to json
jsonBytes, err := ioutil.ReadFile(filepath.Join(extDir, fname))
abortErr(err)
jsonBytes = removeJsoncComments(jsonBytes)
GVerbose.Trace("file content: %s", string(jsonBytes))
var uploaderDef map[string]interface{}
err = json.Unmarshal(jsonBytes, &uploaderDef)

abortErr(err)
if FromGoRet[string](xmap.GetDeep[string](uploaderDef, `meta.id`)).ValueOrExit() != opt.Uploader {
continue
}
if FromGoRet[string](xmap.GetDeep[string](uploaderDef, "meta.type")).ValueOrExit() != "simple-http-uploader" {
continue
}
uploader = &SimpleHttpUploader{OnUploaded: onUploaded, Definition: uploaderDef}
extConfig, err := loadUploaderConfig[map[string]interface{}](opt.Uploader)
if err == nil {
uploader.Config = extConfig
GVerbose.Trace("uploader config:")
GVerbose.TraceStruct(uploader.Config)
}else{
GVerbose.Trace("no uploader config found")
}
break
}
if nil == uploader {
abortErr(errors.New("unknown uploader: " + opt.Uploader))
}
uploader.UploadAll(opt.LocalPaths, opt.TargetDir)
return

}

func removeJsoncComments(data []byte) []byte {
var buf bytes.Buffer
var inBlockComment bool
var inLineComment bool
for _, b := range data {
if inBlockComment {
if b == '*' && data[len(data)-1] == '/' {
inBlockComment = false
}
continue
}
if inLineComment {
if b == '\n' {
inLineComment = false
}
continue
}
if b == '/' {
if data[len(data)-1] == '/' {
inLineComment = true
continue
}
if data[len(data)-1] == '*' {
inBlockComment = true
continue
}
}
buf.WriteByte(b)
}
return buf.Bytes()
}

func loadClipboard() {
Expand Down
Loading

0 comments on commit dbfe70e

Please sign in to comment.