Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions template/StarryDeserts/code/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
1 change: 1 addition & 0 deletions template/StarryDeserts/code/DParcel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/*
38 changes: 38 additions & 0 deletions template/StarryDeserts/code/DParcel/Move.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "dparcel"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move
# license = "" # e.g., "MIT", "GPL", "Apache 2.0"
# authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"]

[dependencies]

Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet", override = true }

# For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`.
# Revision can be a branch, a tag, and a commit hash.
# MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" }

# For local dependencies use `local = path`. Path is relative to the package root
# Local = { local = "../path/to" }

# To resolve a version conflict and force a specific version for dependency
# override use `override = true`
# Override = { local = "../conflicting/version", override = true }

[addresses]
dparcel = "0x0"

# Named addresses will be accessible in Move as `@name`. They're also exported:
# for example, `std = "0x1"` is exported by the Standard Library.
# alice = "0xA11CE"

[dev-dependencies]
# The dev-dependencies section allows overriding dependencies for `--test` and
# `--dev` modes. You can introduce test-only dependencies here.
# Local = { local = "../path/to/dev-build" }

[dev-addresses]
# The dev-addresses section allows overwriting named addresses for the `--test`
# and `--dev` modes.
# alice = "0xB0B"

190 changes: 190 additions & 0 deletions template/StarryDeserts/code/DParcel/sources/DParcel.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
module dparcel::dparcel;

use std::string::{Self, String};
use sui::random;
use sui::random::Random;
use sui::table::{Self, Table};

public struct KUAIDI has drop {}

// 错误码
const EKeyDoesNotExist: u64 = 0;

public struct WalrusStorageInfo has key {
id: UID,
storage_info: Table<address, Table<String, String>>, // 用户地址 |-> <取件码 -> 文件名>
pickup_code: Table<String, String>, // 取件码 |-> Walrus blobID
code_to_uploader: Table<String, address>, // 取件码 |-> 上传者地址
user_pickup_codes: Table<address, vector<String>>, // 用户地址 |-> 取件码列表
pickup_code_file_name: Table<String, String>, // 取件码 |-> 文件名
}

// 文件信息
public struct FileInfo has copy {
file_name: String,
pickup_code: String,
}

// 查询的文件信息
public struct QueryFileInfo has copy {
walrus_blob_id: String,
file_name: String,
}

fun init(otw: KUAIDI, ctx: &mut TxContext) {
// 发布者声明,一次性见证
let publisher = sui::package::claim(otw, ctx);
let walrus_storage_info = WalrusStorageInfo {
id: object::new(ctx),
storage_info: table::new(ctx),
pickup_code: table::new(ctx),
code_to_uploader: table::new(ctx),
user_pickup_codes: table::new(ctx),
pickup_code_file_name: table::new(ctx),
};
// 将发布者的转给发布者
transfer::public_transfer(publisher, ctx.sender());
// 将主存储设置为共享对象
transfer::share_object(walrus_storage_info);
}

// 上传文件
entry fun upload_file(
walrus_storage_info: &mut WalrusStorageInfo,
file_name: String,
walrus_blob_id: String,
random: &Random,
ctx: &mut TxContext,
) {
let pickup_code = generate_pickup_code(random, ctx); // 生成取件码
table::add(&mut walrus_storage_info.pickup_code, pickup_code, walrus_blob_id);
table::add(&mut walrus_storage_info.code_to_uploader, pickup_code, ctx.sender());
table::add(&mut walrus_storage_info.pickup_code_file_name, pickup_code, file_name);

// 更新 storage_info
if (table::contains(&walrus_storage_info.storage_info, ctx.sender())) {
let pickup_code_list = table::borrow_mut(&mut walrus_storage_info.storage_info, ctx.sender());
table::add(pickup_code_list, pickup_code, file_name);

// 更新 user_pickup_codes
let user_codes = table::borrow_mut(&mut walrus_storage_info.user_pickup_codes, ctx.sender());
vector::push_back(user_codes, pickup_code);
} else {
let mut pickup_code_list = table::new<String, String>(ctx);
table::add(&mut pickup_code_list, pickup_code, file_name);
table::add(&mut walrus_storage_info.storage_info, ctx.sender(), pickup_code_list);

let mut user_codes = vector::empty<String>();
vector::push_back(&mut user_codes, pickup_code);
table::add(&mut walrus_storage_info.user_pickup_codes, ctx.sender(), user_codes);
}
}

// 下载文件
public entry fun download_file(
walrus_storage_info: &mut WalrusStorageInfo,
pickup_code: String
) {
// 检查取件码是否存在
if (!table::contains(&walrus_storage_info.pickup_code, pickup_code)) {
pickup_code_not_exist();
};
table::remove(&mut walrus_storage_info.pickup_code, pickup_code);
let uploader_address = table::remove(&mut walrus_storage_info.code_to_uploader, pickup_code);

// 从 storage_info 中删除
let pickup_code_list = table::borrow_mut(&mut walrus_storage_info.storage_info, uploader_address);
if (!table::contains(pickup_code_list, pickup_code)) {
pickup_code_not_exist();
};
table::remove(pickup_code_list, pickup_code);

// 从 user_pickup_codes 中删除
let user_codes = table::borrow_mut(&mut walrus_storage_info.user_pickup_codes, uploader_address);
let (found, index) = vector::index_of(user_codes, &pickup_code);
if (found) {
vector::remove(user_codes, index);
};
}

entry fun seal_approve(walrus_storage_info: &WalrusStorageInfo, pickup_code: String) {
// 检查取件码是否存在
if (!table::contains(&walrus_storage_info.pickup_code, pickup_code)) {
pickup_code_not_exist();
};
}

/// private function

fun generate_pickup_code(random: &Random, ctx: &mut TxContext): String {
let mut generator = random::new_generator(random, ctx);
let random_bytes = random::generate_bytes(&mut generator, 8);
bytes_to_hex(&random_bytes)
}

fun bytes_to_hex(bytes: &vector<u8>): String {
let hex_chars = b"0123456789abcdef";
let mut result = vector::empty<u8>();
let len = vector::length(bytes);
let mut i = 0;
while (i < len) {
let byte = bytes[i];
vector::push_back(&mut result, hex_chars[(byte >> 4 as u64)]);
vector::push_back(&mut result, hex_chars[(byte & 0x0F as u64)]);
i = i + 1;
};
string::utf8(result)
}

/// view function

public fun get_pickup_code_list(
walrus_storage_info: &WalrusStorageInfo,
user_address: address,
): vector<FileInfo> {
// 如果用户没有上传过文件,返回空列表
if (!table::contains(&walrus_storage_info.user_pickup_codes, user_address)) {
return vector::empty<FileInfo>()
};

let user_codes = table::borrow(&walrus_storage_info.user_pickup_codes, user_address);
let file_info_table = table::borrow(&walrus_storage_info.storage_info, user_address);

let mut files = vector::empty<FileInfo>();
let len = vector::length(user_codes);
let mut i = 0;
while (i < len) {
let pickup_code = vector::borrow(user_codes, i);
let file_name = table::borrow(file_info_table, *pickup_code);
let file_info = FileInfo {
file_name: *file_name,
pickup_code: *pickup_code,
};
vector::push_back(&mut files, file_info);
i = i + 1;
};
files
}

public fun get_blob_id_from_pickup_code(
walrus_storage_info: &WalrusStorageInfo,
pickup_code: String
): QueryFileInfo {
if (!table::contains(&walrus_storage_info.pickup_code, pickup_code)) {
pickup_code_not_exist();
};
let walrus_id = table::borrow(&walrus_storage_info.pickup_code, pickup_code);
let file_name = table::borrow(&walrus_storage_info.pickup_code_file_name, pickup_code);
let query_file_info = QueryFileInfo {
walrus_blob_id: *walrus_id,
file_name: *file_name,
};
query_file_info
}

/// error handing
fun pickup_code_not_exist() {
abort(EKeyDoesNotExist)
}


18 changes: 18 additions & 0 deletions template/StarryDeserts/code/DParcel/tests/DParcelsui_test.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
#[test_only]
module kuaidi::kuaidi_tests;
// uncomment this line to import the module
// use kuaidi::kuaidi;

const ENotImplemented: u64 = 0;

#[test]
fun test_kuaidi() {
// pass
}

#[test, expected_failure(abort_code = ::kuaidi::kuaidi_tests::ENotImplemented)]
fun test_kuaidi_fail() {
abort ENotImplemented
}
*/
16 changes: 16 additions & 0 deletions template/StarryDeserts/code/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({
baseDirectory: __dirname,
});

const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];

export default eslintConfig;
14 changes: 14 additions & 0 deletions template/StarryDeserts/code/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
eslint: {
// 在生产构建时忽略ESLint错误
ignoreDuringBuilds: true,
},
typescript: {
// 在生产构建时忽略TypeScript错误
ignoreBuildErrors: true,
},
// 其他Next.js配置...
};

module.exports = nextConfig;
11 changes: 11 additions & 0 deletions template/StarryDeserts/code/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
/* config options here */
output: 'export', // 打包为静态文件
images: {
unoptimized: true, // 禁用图片优化API,解决与静态导出模式的兼容问题
},
};

export default nextConfig;
Loading