当前位置:网站首页>Paste board based on curl and COS

Paste board based on curl and COS

2022-06-24 03:34:00 Wang Lei -ai Foundation

background

A lot of times , We need a temporary pasteboard , Sometimes we can use the chat tool as a pasteboard , Or find a similar service on the Internet for pasting . But there are obviously many limitations to doing so , Except not enough geek outside , There are many occasions , We need this sticker to work with other unix Class tools , Make up some more complex scripts .

So can we do a project based on curl The pasteboard tool , Temporary pasted content is also easier to handle , Just store it in the object store , Here we use the... On Tencent cloud cos Storage is a small tool 【cos The free quota of should be enough for us to use 】

Realization

First of all, this service is a http service , It needs to have the following functions :

  1. Support writing arbitrary binary data
  2. After writing the data, it returns a Clipboard id, adopt This id Data can be returned
  3. use curl Can use
  4. Support regular cleaning of old pasteboard data
  5. Store data to cos On
  6. other , such as size Limit ,qps Limit etc.

This is a very simple tool , The code implemented does not exceed 200 That's ok

var (
	DefaultTTL = flag.Duration("default_ttl", time.Hour*24*7, "default ttl for object")
	RateLimit  = flag.Int("rate_limit", 1, "rate limit for api call")
	SizeLimit  = flag.Int64("size_limit", 1024*1024*10, "size limit for object in byte")
	OSSecret   = flag.String("os_secret", "::", "secret key for object storage, format: key:id:session")
	BucketUrl  = flag.String("bucket_url", "", "bucket_url for object storage")
	NameLength = flag.Int("name_length", 4, "name length for object put")
)

func main() {
	flag.Parse()
	rand.Seed(time.Now().UnixNano())

	key, secret, token := "", "", ""
	if os.Getenv("os_secret") != "" {
		*OSSecret = os.Getenv("os_secret")
	}
	if os.Getenv("bucket_url") != "" {
		*BucketUrl = os.Getenv("bucket_url")
	}
	secretList := strings.Split(*OSSecret, ":")
	if len(secretList) >= 1 {
		key = secretList[0]
	}
	if len(secretList) >= 2 {
		secret = secretList[1]
	}
	if len(secretList) >= 3 {
		token = secretList[2]
	}

	u, err := url.Parse(*BucketUrl)
	if err != nil {
		panic("bucket url not valid")
	}
	client := cos.NewClient(&cos.BaseURL{BucketURL: u}, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:     key,
			SecretKey:    secret,
			SessionToken: token,
		},
	})

	go expireJob(client)

	s := &http.Server{
		Addr:           ":80",
		ReadTimeout:    60 * time.Second,
		WriteTimeout:   60 * time.Second,
		MaxHeaderBytes: 1 << 10,
	}

	limiter := rate.NewLimiter(rate.Limit(*RateLimit), *RateLimit)
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
		defer cancel()

		_ = limiter.Wait(ctx)

		if request.Method == "POST" {
			log.Printf("[Handle] Method=Post Content-Length=%d", request.ContentLength)
			if *SizeLimit > 0 && request.ContentLength > *SizeLimit {
				writer.WriteHeader(400)
				_, _ = writer.Write([]byte(fmt.Sprintf("content size out of limit: %d", *SizeLimit)))
				return
			}
			name := fmt.Sprintf("%s/%s", time.Now().Format("20060102"), randName())
			resp, err := client.Object.Put(ctx, name, request.Body, &cos.ObjectPutOptions{
				ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{},
			})
			if err != nil {
				if resp != nil {
					writer.WriteHeader(resp.StatusCode)
				} else {
					writer.WriteHeader(400)
				}
				log.Printf("[Handle] put file failed: %s", err)
				_, _ = writer.Write([]byte("put file failed"))
				return
			}
			writer.WriteHeader(resp.StatusCode)
			_, _ = writer.Write([]byte(encodeName(name)))
		} else if request.Method == "GET" {
			name, err := decodeName(strings.Trim(request.URL.Path, "/"))
			log.Printf("[Handle] Method=Get Name=%s", name)
			if err != nil {
				writer.WriteHeader(400)
				log.Printf("[Handle] file not valid: %s", err)
				_, _ = writer.Write([]byte("file name not valid"))
				return
			}
			resp, err := client.Object.Get(ctx, name, nil)
			if err != nil {
				if resp != nil {
					writer.WriteHeader(resp.StatusCode)
				} else {
					writer.WriteHeader(400)
				}
				log.Printf("[Handle] get file failed: %s", err)
				_, _ = writer.Write([]byte("get file failed"))
				return
			}
			data, _ := ioutil.ReadAll(resp.Body)
			_, _ = writer.Write(data)
		}
	})
	log.Println("starting server...")
	log.Fatal(s.ListenAndServe())
}

func expireJob(client *cos.Client) {
	for range time.Tick(time.Minute * 10) {
		log.Println("do expire....")
		expireTo := time.Now().Add(-1 * *DefaultTTL)

		var cleaned []string
		for day := 1; day <= 30; day++ {
			toDelDay := expireTo.Add(time.Duration(day) * time.Hour * 24 * -1)
			name := toDelDay.Format("20060102") + "/"
			ctx := context.Background()
			resp, err := client.Object.Head(ctx, name, nil)
			if err != nil {
				if resp != nil && resp.StatusCode == 404 {
					continue
				}
				log.Println("head object failed, ", err)
				continue
			}
			if resp.StatusCode != 200 {
				continue
			}
			resp, err = client.Object.Delete(ctx, name, nil)
			if err != nil {
				log.Println("delete object failed, ", err)
				continue
			}
			if resp.StatusCode != 200 {
				log.Println("delete object failed, ", resp.Status)
			} else {
				cleaned = append(cleaned, name)
				log.Printf("expire old folder: %s success", name)
			}
		}
		log.Println("do expire done:", cleaned)
	}
}

Use docker Deploy ,dockerfile as follows

FROM alpine
ADD bin/clipboard /usr/local/bin
ENTRYPOINT ["clipboard"]

demonstration

#  Example  1
* curl 148.70.103.38:30744 -d "hello"
20210925Vd4h%                                                                                                                                                     

* curl 148.70.103.38:30744/20210925Vd4h
hello%                                                                                                                                                   


#  Example  2                                                                   
* curl 148.70.103.38:30744 -d '{"someJsonData"}'
20210925aHiw%  

* curl 148.70.103.38:30744/20210925aHiw
{"someJsonData"}%


#  Example 3:  Upload a picture 
* curl 148.70.103.38:30744 --data-binary @`pwd`/test.png
20210925fzul%                                                                                                                                                                                                               
* curl 148.70.103.38:30744/20210925fzul > test1.png
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 70858    0 70858    0     0   162k      0 --:--:-- --:--:-- --:--:--  162k

The complete project code is in here

原网站

版权声明
本文为[Wang Lei -ai Foundation]所创,转载请带上原文链接,感谢
https://yzsam.com/2021/09/20210925234947965M.html

随机推荐