Skip to content

Commit 5289a71

Browse files
committed
build: release docker image by GitHubActions, add docker image for
spa-client doc: add docker image for spa-client improve: add debug log for spa-server request
1 parent e1952e2 commit 5289a71

15 files changed

+170
-44
lines changed

.dockerignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
target
22
tmp
33
.git
4-
.github
4+
.github
5+
doc
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: sap-client docker release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
tag:
7+
required: true
8+
description: "git tag to release"
9+
10+
jobs:
11+
docker:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v3
15+
with:
16+
submodules: true
17+
-
18+
name: Set up QEMU
19+
uses: docker/setup-qemu-action@v1
20+
-
21+
name: Set up Docker Buildx
22+
uses: docker/setup-buildx-action@v1
23+
-
24+
name: Login to DockerHub
25+
uses: docker/login-action@v1
26+
with:
27+
username: ${{ secrets.DOCKERHUB_USERNAME }}
28+
password: ${{ secrets.DOCKERHUB_TOKEN }}
29+
-
30+
name: Build and push
31+
uses: docker/build-push-action@v2
32+
with:
33+
context: .
34+
file: SPA-Client.Dockerfile
35+
platforms: linux/amd64,linux/arm64
36+
push: true
37+
tags: timzaak/spa-client:${{github.event.inputs.tag}}

Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# -*- mode: dockerfile -*-
22

3+
# Dockerfile for spa-server
4+
35
# You can override this `--build-arg BASE_IMAGE=...` to use different
46
# version of Rust
57
ARG BASE_IMAGE=rust:1.59

Makefile

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# All is from https://github.com/extrawurst/gitui
22
SPC_CLIENT_JS_DIR = jsclient
33

4-
.PHONY: build-spa-client-js, build-release, release-mac, release-win, release-linux-musl, docker-release
4+
.PHONY: build-spa-client-js, build-release, release-mac, release-win, release-linux-musl, docker-release, spa-client-docker-release
55

66
build-release:
77
cargo build --package spa-client --release
@@ -43,3 +43,11 @@ else
4343
DOCKER_BUILDKIT=1 docker build . -t="timzaak/spa-server:$(VERSION)"
4444
docker push timzaak/spa-server:$(VERSION)
4545
endif
46+
47+
spa-client-docker-release:
48+
ifeq ($(VERSION), )
49+
$(error VEDRSION is not set)
50+
else
51+
DOCKER_BUILDKIT=1 docker build . -f SPA-Client.Dockerfile -t="timzaak/client:$(VERSION)"
52+
docker push timzaak/spa-client:$(VERSION)
53+
endif

SPA-Client.Dockerfile

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# -*- mode: dockerfile -*-
2+
3+
# Dockerfile for spa-server
4+
5+
# You can override this `--build-arg BASE_IMAGE=...` to use different
6+
# version of Rust
7+
ARG BASE_IMAGE=rust:1.59
8+
9+
ARG RUNTIME_IMAGE=debian:buster-slim
10+
11+
# Our first FROM statement declares the build environment.
12+
FROM ${BASE_IMAGE} AS builder
13+
14+
# Add our source code.
15+
ADD . .
16+
17+
# Build our application.
18+
RUN --mount=type=cache,target=/usr/local/cargo/registry \
19+
cargo build --package spa-client --release
20+
21+
FROM ${RUNTIME_IMAGE}
22+
23+
COPY --from=builder ./target/release/spa-client /usr/bin
24+
25+
CMD ["spa-client"]

client/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "spa-client"
3-
version = "1.2.3"
3+
version = "0.1.0"
44
edition = "2021"
55
authors = ["timzaak"]
66
license = "MIT"
@@ -11,7 +11,7 @@ categories = ["command-line-utilities", "accessibility", "web-programming::http-
1111

1212
include = ["src/**/*", "Cargo.toml"]
1313

14-
rust-version = "1.59"
14+
#rust-version = "1.59"
1515

1616
[[bin]]
1717
name = "spa-client"

client/client_config_default.conf

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# admin server, if set --config-dir
2+
server {
3+
address: "http://127.0.0.1:9000"
4+
auth_token: "token"
5+
}
6+
7+
upload {
8+
# default value is:3
9+
parallel: 3
10+
}

client/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod commands;
66
mod config;
77
mod upload_files;
88

9+
use anyhow::Context;
910
use crate::api::API;
1011
use crate::commands::{CliCommand, Commands};
1112
use crate::config::Config;
@@ -40,7 +41,8 @@ fn success(message: &str) {
4041
}
4142

4243
fn run_with_commands(commands: CliCommand) -> anyhow::Result<()> {
43-
let config = Config::load(commands.config_dir)?;
44+
let config = Config::load(commands.config_dir)
45+
.with_context(||"Please set config, you can get help at https://github.com/timzaak/spa-server/blob/master/doc/SPA-Client.md#how-to-use-commandline-of-spa-client")?;
4446
println!(
4547
"spa-client connect to admin server({})",
4648
&config.server.address

doc/Roadmap.md

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
# Roadmap
22
### Version 1.3.x
3-
Now there is no real roadmap for V1.3.x, need users.
3+
Now there is no real roadmap for v1.3.x, need users.
44

5-
### Version 1.2.4
5+
### Version 1.2.5
6+
- [ ] make release trigger by tag
7+
8+
9+
### Version 1.2.4(client:v0.2.0)
610
- [ ] release commandline of spa-client for mac/ios/linux (by GitHub Actions), put them with GitHub release page
7-
- [ ] fix possible bugs about uploading and spa-client(-js)
8-
- [ ] improve doc, ready to get the world known it.
11+
- [x] fix possible bugs about uploading and spa-client(-js)
12+
- [ ] doc: improve doc, ready to get the world known it.
13+
- [x] build: release docker image by GitHubActions
14+
- [x] build: add docker image for spa-client
15+
- [x] doc: how to use spa-client image
16+
- [x] improve: add debug log for spa-server request
917

10-
### version 1.2.3
18+
### version 1.2.3(client:v0.1.0)
1119
- [x] admin server export http api to accept files to local file system
1220
- [x] add client to sync local files to admin server(retry support)
1321
- [ ] ~~release server/client to crate~~ [crate needs dep version, need replace warp firstly](https://github.com/rust-lang/cargo/issues/1565)

doc/SPA-Client.md

+7
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,10 @@ curl "http://$ADMIN_SERVER/update_version?domain=$DOMAIN" -H "Authorization: Bea
3232
```
3333

3434
All the admin server http api is in the [Admin_Server_API.md](./doc/Admin_Server_API.md).
35+
36+
37+
## spa-client docker image
38+
there is an example of using spa-client docker image
39+
```shell
40+
docker run --rm -it -v $CONFIG_FILE_PATH:/client.conf timzaak/client spa-client -c /client.conf info
41+
```

doc/design/Uploading_File_Process.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ Firstly, there are lots of files needed upload, so `retry` and `correct` must be
55
there also may exist large files which more than 20M(we would consider it later, we have lots work to do to support
66
resume breakpoint).
77

8-
So the admin-server should provider an api to show file metadata and status in server of the selected domain version.
9-
according to file metadata on the server side, `spa-client` could decide which file should be uploaded and which not,
8+
So the admin-server should provider api to show file metadata for checking file md5 and uploading status in server to avoid uploading conflict.
9+
10+
According to file metadata on the server side, `spa-client` could decide which file should be uploaded and which not,
1011
this could save time when network errors happen.
1112

12-
Admin-server also need to know which version is in the process of receiving files after restart. So when the
13+
Admin-server also need to know which version is in the process of receiving files after restart. So when
1314
`spa-client` begin to upload file, it should tell admin-server, and admin-server add a file `.SPA-Processing` to
1415
the directory `$Domain/$Version` if it not exists. admin-server will also reject the client uploading file if the
1516
version is not set `.SPA-Prpccessing`. When `spa-client` tell admin-server uploading is finished, admin-server should
1617
remove the file `.SPA-Processing`. The version which has `.SPA-Processing` should not be allowed to be online.
1718

1819

19-
The above article do not consider how to deal with `S3` storage, I may later bring `S3` http client to admin-server
20-
or `spa-client`, and do some work to improve the performance of `S3` files which are not cached in server.
20+
The above article do not consider how to deal with `S3` storage, we may later bring `S3` http client to admin-server
21+
or `spa-client`, and do some work to improve the performance of `S3` files which are not cached in `spa-server`.

example/js-app-example/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ npm install spa-client --save-dev
1616
```
1717
2. add configs for spa-client in the [.env](.env) file
1818

19-
3. Add script to package.json (need `dotenv` to inject config, you can also use config file as [SPA-Client](../../doc/SPA-Client.md)) said.
19+
3. Add script to package.json (need `dotenv` to inject config, you can also use config file as [SPA-Client](../../doc/SPA-Client.md) said).
2020

2121
```json
2222
{
2323
"script":{
2424
"upload": "dotenv .env.prod spa-client upload ./build www.example.com",
25-
"release":"dotenv .env.prod spa-client release www.baidu.com"
25+
"release":"dotenv .env.prod spa-client release www.example.com"
2626
}
2727
}
2828
```
@@ -33,7 +33,7 @@ if you don't want to use `dotenv`, just like this, the config file is like [clie
3333
{
3434
"script":{
3535
"upload": "spa-client upload ./build www.example.com --config-dir $CONFIG_PATH",
36-
"release": "spa-client release www.baidu.com --config-dir $CONFIG_PATH"
36+
"release": "spa-client release www.example.com --config-dir $CONFIG_PATH"
3737
}
3838
}
3939
```

jsclient/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# SPA-Client
22
This is a wrapper of Rust commandline for [spa-server](https://github.com/timzaak/spa-server),
3-
please read the doc [SPA_Client.md](https://github.com/timzaak/spa-server/blob/master/doc/SPA-Client.md) to more information
4-
about it, and there is also an example to quick start: [js-app-example](https://github.com/timzaak/spa-server/tree/master/example/js-app-example)
3+
please read the doc [SPA_Client.md](https://github.com/timzaak/spa-server/blob/master/doc/SPA-Client.md) to get more information ,
4+
and there is also an example to quick start: [js-app-example](https://github.com/timzaak/spa-server/tree/master/example/js-app-example)

server/src/file_cache.rs

+10
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ pub enum DataBlock {
151151
// for use warp
152152
FileBlock(ArcPath),
153153
}
154+
/*
155+
impl DataBlock {
156+
pub fn get_path(&self) -> &ArcPath {
157+
match self {
158+
DataBlock::CacheBlock {path,..} => path,
159+
DataBlock::FileBlock(path) => path,
160+
}
161+
}
162+
}
163+
*/
154164

155165
pub struct CacheItem {
156166
pub meta: Metadata,

server/src/static_file_filter.rs

+39-24
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,17 @@ fn cache_reply(
176176
}
177177

178178
async fn cache_or_file_reply(
179-
item: Arc<CacheItem>,
179+
item: (String, Arc<CacheItem>),
180180
conditionals: Conditionals,
181181
accept_encoding: Option<String>,
182182
) -> Result<Response<Body>, Rejection> {
183+
let (key, item) = item;
183184
let modified = item.meta.modified().map(LastModified::from).ok();
184185
match conditionals.check(modified) {
185-
Cond::NoBody(resp) => Ok(resp),
186+
Cond::NoBody(resp) => {
187+
tracing::debug!("{} hit client cache", key);
188+
Ok(resp)
189+
},
186190
Cond::WithBody(range) => match &item.data {
187191
DataBlock::CacheBlock {
188192
bytes,
@@ -200,16 +204,23 @@ async fn cache_or_file_reply(
200204
//false,false => cache without content-encoding
201205
//false, true => file
202206
if !client_accept_gzip && compressed {
207+
tracing::debug!("{} hit disk", key);
203208
file_reply(&item, path.as_ref(), range, modified).await
204209
} else {
205210
let mut resp = cache_reply(item.as_ref(), bytes, range, modified);
206211
if client_accept_gzip && compressed {
212+
tracing::debug!("{} hit cache, compressed", key);
207213
resp.headers_mut().typed_insert(ContentEncoding::gzip());
214+
}else {
215+
tracing::debug!("{} hit cache", key);
208216
}
209217
Ok(resp)
210218
}
211219
}
212-
DataBlock::FileBlock(path) => file_reply(&item, path.as_ref(), range, modified).await,
220+
DataBlock::FileBlock(path) => {
221+
tracing::debug!("{} hit disk", key);
222+
file_reply(&item, path.as_ref(), range, modified).await
223+
},
213224
},
214225
}
215226
}
@@ -239,33 +250,37 @@ fn cache_item_to_response_header(
239250
}
240251
}
241252

242-
pub fn static_file_filter(
253+
async fn get_cache_file(
254+
tail: warp::path::Tail,
255+
authority_opt: Option<Authority>,
243256
domain_storage: Arc<DomainStorage>,
244-
) -> impl Filter<Extract = (Response<Body>,), Error = Rejection> + Clone {
245-
async fn get_cache_file(
246-
tail: warp::path::Tail,
247-
authority_opt: Option<Authority>,
248-
domain_storage: Arc<DomainStorage>,
249-
) -> Result<Arc<CacheItem>, Rejection> {
250-
match authority_opt {
251-
Some(authority) => {
252-
let key = sanitize_path(tail.as_str()).map(|s| {
253-
if s.is_empty() {
254-
"index.html".to_owned()
255-
} else {
256-
s
257-
}
258-
})?;
259-
let host = authority.host();
260-
if let Some(cache_item) = domain_storage.get_file(host, &key) {
261-
Ok(cache_item)
257+
) -> Result<(String,Arc<CacheItem>), Rejection> {
258+
match authority_opt {
259+
Some(authority) => {
260+
let key = sanitize_path(tail.as_str()).map(|s| {
261+
if s.is_empty() {
262+
"index.html".to_owned()
262263
} else {
263-
Err(reject::not_found())
264+
s
264265
}
266+
})?;
267+
let host = authority.host();
268+
if let Some(cache_item) = domain_storage.get_file(host, &key) {
269+
Ok((key, cache_item))
270+
} else {
271+
tracing::debug!("no file for: {}/{}", &host, &key);
272+
Err(reject::not_found())
265273
}
266-
None => Err(reject::not_found()),
267274
}
275+
None => {
276+
tracing::warn!("No Authority Request");
277+
Err(reject::not_found())
278+
},
268279
}
280+
}
281+
pub fn static_file_filter(
282+
domain_storage: Arc<DomainStorage>,
283+
) -> impl Filter<Extract = (Response<Body>,), Error = Rejection> + Clone {
269284
warp::get()
270285
.or(warp::head())
271286
.unify()

0 commit comments

Comments
 (0)