Files
craftlabs-authorization-sdk/docs/superpowers/plans/2026-05-01-bitanswer-1to1-refactor.md
T
huangping 307a019d48 plan: implement BitAnswer 1:1 refactor — 12 tasks across 4 phases
Phase 1 (infrastructure, no breaking changes):
- Rust: error.rs, session.rs, ffi/bitanswer.rs, ffi/bridge.rs
- Rust: refactor lib.rs to session-based handle management
- Java: @Deprecate AuthProvider, create 6 capability interfaces
- Java: LicenseSession skeleton, NativeBridge 30+ method stubs
- Java: CraftLicense new entry point

Phase 2-4: core API expansion, advanced features, cleanup
2026-05-01 13:57:46 +08:00

1602 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BitAnswer 1:1 映射重构 实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 将 craftlabs-authorization-sdk 的 SDK 客户端层从 8 方法 AuthProvider 重构为 BitAnswer C API 的 1:1 原语映射,按 6 个能力接口分层,4 个 Phase 渐进交付。
**Architecture:** Java 侧分为 CraftLicense(入口)+ LicenseSession(实现 6 个能力接口:LicenseLifecycle、FeatureManagement、DataItemStore、LicenseInfoQuery、CheckoutManager、LicenseUtility)。Rust 侧新增 ffi/bitanswer.rsBitAnswer C API FFI 声明)、ffi/bridge.rscraft_* → Bit_* 桥接)、session.rs(句柄管理)、error.rs(错误码映射)。Phase 1 不破坏现有接口。
**Tech Stack:** Rust (cdylib, libloading), Java 17 (Maven multi-module), JNI, BitAnswer C SDK
**Spec reference:** `docs/superpowers/specs/2026-05-01-bitanswer-1to1-refactor-design.md`
---
## Phase 1 — 基础设施(不破坏现有接口)
### Task 1: Rust — 创建 error.rs(错误码映射)
**Files:**
- Create: `native/craft-core/src/error.rs`
- [ ] **Step 1: 创建 LicenseError 枚举**
写入 `native/craft-core/src/error.rs`
```rust
use crate::CraftResult;
/// BitAnswer BIT_STATUS 错误码到结构化错误的精简映射。
/// 完整 200+ 码请参考 bitanswer.h,此处映射文档中明确列出的高频码。
#[derive(Debug, Clone, PartialEq)]
pub enum LicenseError {
Success,
NetworkError,
WrongHandle,
InvalidParameter,
ApplicationDataError,
LicenseExpired,
LicenseNotFound,
LicenseDisabled,
FeatureNotFound(u32),
FeatureExpired(u32),
FeatureTypeNotMatch(u32),
SnInvalid,
SnNotFound,
SnDisabled,
SnRevoked,
SnExpired,
CapacityExhausted,
ServerBusy,
ServerDown,
Timeout,
Unknown(u32),
}
impl LicenseError {
/// 将 BitAnswer BIT_STATUS (u32) 映射为 LicenseError
pub fn from_bit_status(status: u32) -> Self {
match status {
0x0000 => LicenseError::Success,
0x0101 => LicenseError::NetworkError,
0x0102 => LicenseError::WrongHandle,
0x0103 => LicenseError::InvalidParameter,
0x0105 => LicenseError::ApplicationDataError,
0x0701 => LicenseError::LicenseExpired,
0x0114 => LicenseError::LicenseNotFound,
0x0705 => LicenseError::LicenseDisabled,
0x0503 => LicenseError::FeatureNotFound(0),
0x0509 => LicenseError::FeatureExpired(0),
0x0504 => LicenseError::FeatureTypeNotMatch(0),
0x011C => LicenseError::SnInvalid,
0x0706 => LicenseError::SnNotFound,
0x0705 => LicenseError::SnDisabled,
0x0123 => LicenseError::SnRevoked,
0x0701 => LicenseError::SnExpired,
0x0712 => LicenseError::CapacityExhausted,
0x0107 => LicenseError::ServerBusy,
0x0108 => LicenseError::ServerDown,
0x0141 => LicenseError::Timeout,
_ => LicenseError::Unknown(status),
}
}
pub fn message(&self) -> &'static str {
match self {
LicenseError::Success => "ok",
LicenseError::NetworkError => "network error",
LicenseError::WrongHandle => "wrong handle",
LicenseError::InvalidParameter => "invalid parameter",
LicenseError::ApplicationDataError => "application data error",
LicenseError::LicenseExpired => "license expired",
LicenseError::LicenseNotFound => "license not found",
LicenseError::LicenseDisabled => "license disabled",
LicenseError::FeatureNotFound(_) => "feature not found",
LicenseError::FeatureExpired(_) => "feature expired",
LicenseError::FeatureTypeNotMatch(_) => "feature type not match",
LicenseError::SnInvalid => "sn invalid",
LicenseError::SnNotFound => "sn not found",
LicenseError::SnDisabled => "sn disabled",
LicenseError::SnRevoked => "sn revoked",
LicenseError::SnExpired => "sn expired",
LicenseError::CapacityExhausted => "capacity exhausted",
LicenseError::ServerBusy => "server busy",
LicenseError::ServerDown => "server down",
LicenseError::Timeout => "timeout",
LicenseError::Unknown(_) => "unknown error",
}
}
pub fn is_success(&self) -> bool {
matches!(self, LicenseError::Success)
}
}
/// 将 LicenseError 转为 C ABI 兼容的 CraftResult
pub fn to_craft_result(error: LicenseError) -> CraftResult {
if error.is_success() {
crate::ok_result()
} else {
// 使用堆分配的消息指针(调用方通过 craft_free_license_info 类似方式释放)
let msg = format!("{}\0", error.message());
let msg_ptr = msg.as_ptr() as *const std::os::raw::c_char;
std::mem::forget(msg); // 内存由调用方管理
CraftResult {
success: 0,
message: msg_ptr,
}
}
}
```
- [ ] **Step 2: 在 lib.rs 中注册 error 模块**
`native/craft-core/src/lib.rs``mod` 声明区域添加:
```rust
mod error;
```
- [ ] **Step 3: 编译验证**
```bash
cargo build --manifest-path native/craft-core/Cargo.toml
```
Expected: 编译成功,无错误。
- [ ] **Step 4: 提交**
```bash
git add native/craft-core/src/error.rs native/craft-core/src/lib.rs
git commit -m "feat(native): add LicenseError enum with BitAnswer error code mapping"
```
---
### Task 2: Rust — 创建 session.rs(会话管理)
**Files:**
- Create: `native/craft-core/src/session.rs`
- [ ] **Step 1: 创建 SessionState 和全局会话表**
写入 `native/craft-core/src/session.rs`
```rust
use std::collections::HashMap;
use std::sync::Mutex;
use once_cell::sync::Lazy;
/// 单个会话的运行时状态,映射 Java long (session_id) ↔ BitAnswer BIT_HANDLE
pub struct SessionState {
/// 存储 initialize 时传入的配置 JSON(用于后续 Bit_Login/UpdateOnline
pub config_json: String,
/// Bit_Login / Bit_LoginEx 成功后返回的句柄
pub bit_handle: Option<usize>,
/// 产品识别码(来自 AuthConfig.bitanswer.applicationData
pub application_data: Vec<u8>,
/// 是否已完成 login
pub logged_in: bool,
}
/// 全局会话表:session_id (i64) → SessionState
pub static SESSIONS: Lazy<Mutex<HashMap<i64, SessionState>>> =
Lazy::new(|| Mutex::new(HashMap::new()));
static NEXT_SESSION_ID: Lazy<Mutex<i64>> = Lazy::new(|| Mutex::new(1));
/// 分配一个新的 session_id 并注册 SessionState
pub fn register_session(config_json: String, application_data: Vec<u8>) -> i64 {
let mut next_id = NEXT_SESSION_ID.lock().unwrap();
let id = *next_id;
*next_id += 1;
let mut sessions = SESSIONS.lock().unwrap();
sessions.insert(id, SessionState {
config_json,
bit_handle: None,
application_data,
logged_in: false,
});
id
}
/// 获取 session 的可变引用
pub fn with_session<F, R>(session_id: i64, f: F) -> Option<R>
where
F: FnOnce(&mut SessionState) -> R,
{
let mut sessions = SESSIONS.lock().unwrap();
sessions.get_mut(&session_id).map(f)
}
/// 移除 session
pub fn remove_session(session_id: i64) {
let mut sessions = SESSIONS.lock().unwrap();
sessions.remove(&session_id);
}
```
- [ ] **Step 2: 添加 once_cell 依赖**
`native/craft-core/Cargo.toml``[dependencies]` 区域添加:
```toml
once_cell = "1"
```
- [ ] **Step 3: 在 lib.rs 中注册 session 模块**
`native/craft-core/src/lib.rs``mod` 声明区域添加:
```rust
mod session;
```
- [ ] **Step 4: 编译验证**
```bash
cargo build --manifest-path native/craft-core/Cargo.toml
```
Expected: 编译成功。
- [ ] **Step 5: 提交**
```bash
git add native/craft-core/src/session.rs native/craft-core/src/lib.rs native/craft-core/Cargo.toml
git commit -m "feat(native): add session management with global handle registry"
```
---
### Task 3: Rust — 创建 ffi/bitanswer.rsBitAnswer C API FFI 声明)
**Files:**
- Create: `native/craft-core/src/ffi/mod.rs`
- Create: `native/craft-core/src/ffi/bitanswer.rs`
- [ ] **Step 1: 创建 ffi/mod.rs**
写入 `native/craft-core/src/ffi/mod.rs`
```rust
pub mod bitanswer;
```
- [ ] **Step 2: 创建 bitanswer.rs — BitAnswer C API 的 Rust extern 声明**
写入 `native/craft-core/src/ffi/bitanswer.rs`
```rust
// BitAnswer C API 的 Rust FFI 声明
// 类型定义与 bitanswer.h 对齐
pub type BitHandle = *mut std::ffi::c_void;
pub type BitStatus = u32;
pub type BitUint32 = u32;
// 登录模式常量
pub const BIT_MODE_LOCAL: u32 = 0x01;
pub const BIT_MODE_REMOTE: u32 = 0x02;
pub const BIT_MODE_AUTO: u32 = 0x03;
// 绑定类型
pub const BINDING_EXISTING: u32 = 0;
pub const BINDING_LOCAL: u32 = 1;
// Session 信息类型
pub const XML_TYPE_SN_INFO: u32 = 3;
// Info 类型
pub const BIT_INFO_SN: u32 = 1;
pub const BIT_INFO_SN_FEATURE: u32 = 2;
// 特征查询模式
pub const BIT_QUERY_DEFAULT: u32 = 0x00;
pub const BIT_QUERY_AVAILABLE: u32 = 0x01;
// SetAttr 类型
pub const ATTR_WAIT_TIMEOUT: u32 = 0x2;
pub const ATTR_HB_INTERVAL: u32 = 0x8;
extern "C" {
/// 登录授权
pub fn Bit_Login(
sz_url: *const std::os::raw::c_char,
sz_sn: *const std::os::raw::c_char,
p_application_data: *const u8,
p_handle: *mut BitHandle,
mode: BitUint32,
) -> BitStatus;
/// 特征登录
pub fn Bit_LoginEx(
sz_url: *const std::os::raw::c_char,
sz_sn: *const std::os::raw::c_char,
feature_id: BitUint32,
sz_reserved: *const std::os::raw::c_char,
p_application_data: *const u8,
p_handle: *mut BitHandle,
mode: BitUint32,
) -> BitStatus;
/// Token 登录
pub fn Bit_LoginByToken(
sz_url: *const std::os::raw::c_char,
sz_access_token: *const std::os::raw::c_char,
p_application_data: *const u8,
p_handle: *mut BitHandle,
) -> BitStatus;
/// 登出
pub fn Bit_Logout(handle: BitHandle) -> BitStatus;
/// 在线激活/更新
pub fn Bit_UpdateOnline(
sz_url: *const std::os::raw::c_char,
sz_sn: *const std::os::raw::c_char,
p_application_data: *const u8,
) -> BitStatus;
/// 读取特征值
pub fn Bit_ReadFeature(
handle: BitHandle,
feature_id: BitUint32,
p_feature_value: *mut BitUint32,
) -> BitStatus;
/// 写入特征值
pub fn Bit_WriteFeature(
handle: BitHandle,
feature_id: BitUint32,
feature_value: BitUint32,
) -> BitStatus;
/// 查询特征可用量
pub fn Bit_QueryFeature(
handle: BitHandle,
feature_id: BitUint32,
p_capacity: *mut BitUint32,
) -> BitStatus;
/// 释放特征占用
pub fn Bit_ReleaseFeature(
handle: BitHandle,
feature_id: BitUint32,
p_capacity: *mut BitUint32,
) -> BitStatus;
/// 设置配置项
pub fn Bit_SetDataItem(
handle: BitHandle,
sz_data_item_name: *const std::os::raw::c_char,
p_data_item_value: *const std::ffi::c_void,
data_item_value_size: BitUint32,
) -> BitStatus;
/// 读取配置项
pub fn Bit_GetDataItem(
handle: BitHandle,
sz_data_item_name: *const std::os::raw::c_char,
p_data_item_value: *mut std::ffi::c_void,
p_data_item_value_size: *mut BitUint32,
) -> BitStatus;
/// 删除配置项
pub fn Bit_RemoveDataItem(
handle: BitHandle,
sz_data_item_name: *const std::os::raw::c_char,
) -> BitStatus;
/// 获取配置项数量
pub fn Bit_GetDataItemNum(
handle: BitHandle,
p_num: *mut BitUint32,
) -> BitStatus;
/// 按索引获取配置项名称
pub fn Bit_GetDataItemName(
handle: BitHandle,
index: BitUint32,
p_data_item_name: *mut std::os::raw::c_char,
p_data_item_name_size: *mut BitUint32,
) -> BitStatus;
/// 获取会话信息
pub fn Bit_GetSessionInfo(
handle: BitHandle,
session_type: BitUint32,
p_session_info: *mut std::os::raw::c_char,
p_session_info_size: *mut BitUint32,
) -> BitStatus;
/// 获取授权信息
pub fn Bit_GetInfo(
sz_sn: *const std::os::raw::c_char,
p_application_data: *const u8,
info_type: BitUint32,
p_info: *mut std::os::raw::c_char,
p_info_size: *mut BitUint32,
) -> BitStatus;
/// 浮动迁出 SN
pub fn Bit_CheckOutSn(
sz_url: *const std::os::raw::c_char,
feature_id: BitUint32,
p_application_data: *const u8,
n_duration_days: BitUint32,
) -> BitStatus;
/// 浮动归还
pub fn Bit_CheckIn(
sz_url: *const std::os::raw::c_char,
feature_id: BitUint32,
p_application_data: *const u8,
) -> BitStatus;
/// 撤销授权
pub fn Bit_Revoke(
sz_url: *const std::os::raw::c_char,
sz_sn: *const std::os::raw::c_char,
p_application_data: *const u8,
p_revocation_info: *mut std::os::raw::c_char,
p_revocation_info_size: *mut BitUint32,
) -> BitStatus;
/// 删除本机 SN
pub fn Bit_RemoveSn(
sz_sn: *const std::os::raw::c_char,
p_application_data: *const u8,
) -> BitStatus;
/// 手动心跳
pub fn Bit_Heartbeat(
handle: BitHandle,
p_reconnects_num: *mut BitUint32,
) -> BitStatus;
/// 设置属性
pub fn Bit_SetAttr(
handle: BitHandle,
attr_type: BitUint32,
p_value: *const std::ffi::c_void,
) -> BitStatus;
/// 获取库版本
pub fn Bit_GetVersion(p_version: *mut BitUint32) -> BitStatus;
}
```
- [ ] **Step 3: 在 lib.rs 中注册 ffi 模块**
`native/craft-core/src/lib.rs``mod` 声明区域添加:
```rust
mod ffi;
```
- [ ] **Step 4: 编译验证**
```bash
cargo build --manifest-path native/craft-core/Cargo.toml
```
Expected: 编译成功(extern 声明不会被链接检查,但语法正确)。
- [ ] **Step 5: 提交**
```bash
git add native/craft-core/src/ffi/
git commit -m "feat(native): add BitAnswer C API FFI declarations"
```
---
### Task 4: Rust — 创建 ffi/bridge.rscraft_* → Bit_* 桥接)
**Files:**
- Create: `native/craft-core/src/ffi/bridge.rs`
- [ ] **Step 1: 创建 bridge.rs — Phase 1 核心桥接函数**
写入 `native/craft-core/src/ffi/bridge.rs`
```rust
use crate::error::{LicenseError, to_craft_result};
use crate::ffi::bitanswer;
use crate::session;
use crate::CraftResult;
use std::ffi::CString;
use std::os::raw::c_char;
/// 激活:调用 Bit_UpdateOnline
pub fn bridge_activate(session_id: i64, license_key: &str) -> CraftResult {
let result = session::with_session(session_id, |state| {
// 从配置中解析 URL(简化版:使用固定空 URL → 使用默认服务器)
let url = std::ptr::null(); // NULL 表示使用默认服务器
let sn = match CString::new(license_key) {
Ok(s) => s,
Err(_) => return LicenseError::InvalidParameter,
};
let app_data = state.application_data.as_ptr();
let status = unsafe {
bitanswer::Bit_UpdateOnline(url, sn.as_ptr(), app_data)
};
if status == 0 {
LicenseError::Success
} else {
LicenseError::from_bit_status(status)
}
});
match result {
Some(err) => to_craft_result(err),
None => to_craft_result(LicenseError::WrongHandle),
}
}
/// 登录:调用 Bit_Login
pub fn bridge_login(session_id: i64, sn_str: &str, mode: u32) -> CraftResult {
let result = session::with_session(session_id, |state| {
let url = std::ptr::null();
let sn = match CString::new(sn_str) {
Ok(s) => s,
Err(_) => return LicenseError::InvalidParameter,
};
let app_data = state.application_data.as_ptr();
let mut handle: bitanswer::BitHandle = std::ptr::null_mut();
let status = unsafe {
bitanswer::Bit_Login(url, sn.as_ptr(), app_data, &mut handle, mode)
};
if status == 0 {
state.bit_handle = Some(handle as usize);
state.logged_in = true;
LicenseError::Success
} else {
LicenseError::from_bit_status(status)
}
});
match result {
Some(err) => to_craft_result(err),
None => to_craft_result(LicenseError::WrongHandle),
}
}
/// 登出:调用 Bit_Logout
pub fn bridge_logout(session_id: i64) -> CraftResult {
let result = session::with_session(session_id, |state| {
let handle = match state.bit_handle {
Some(h) => h as bitanswer::BitHandle,
None => return LicenseError::WrongHandle,
};
let status = unsafe { bitanswer::Bit_Logout(handle) };
state.bit_handle = None;
state.logged_in = false;
if status == 0 {
LicenseError::Success
} else {
LicenseError::from_bit_status(status)
}
});
match result {
Some(err) => to_craft_result(err),
None => to_craft_result(LicenseError::WrongHandle),
}
}
/// 心跳:调用 Bit_Heartbeat
pub fn bridge_heartbeat(session_id: i64) -> CraftResult {
let result = session::with_session(session_id, |state| {
let handle = match state.bit_handle {
Some(h) => h as bitanswer::BitHandle,
None => return LicenseError::WrongHandle,
};
let mut reconnects: u32 = 0;
let status = unsafe { bitanswer::Bit_Heartbeat(handle, &mut reconnects) };
if status == 0 {
LicenseError::Success
} else {
LicenseError::from_bit_status(status)
}
});
match result {
Some(err) => to_craft_result(err),
None => to_craft_result(LicenseError::WrongHandle),
}
}
/// 读取特征值:调用 Bit_ReadFeature
pub fn bridge_read_feature(session_id: i64, feature_id: u32) -> i32 {
let result = session::with_session(session_id, |state| {
let handle = match state.bit_handle {
Some(h) => h as bitanswer::BitHandle,
None => return -1i32,
};
let mut value: u32 = 0;
let status = unsafe { bitanswer::Bit_ReadFeature(handle, feature_id, &mut value) };
if status == 0 { value as i32 } else { -1i32 }
});
result.unwrap_or(-1)
}
/// 检查许可:调用 Bit_GetSessionInfo
pub fn bridge_check_license(session_id: i64) -> CraftResult {
let result = session::with_session(session_id, |state| {
let handle = match state.bit_handle {
Some(h) => h as bitanswer::BitHandle,
None => return LicenseError::WrongHandle,
};
let mut buf = vec![0u8; 4096];
let mut size: u32 = 4096;
let status = unsafe {
bitanswer::Bit_GetSessionInfo(handle, bitanswer::XML_TYPE_SN_INFO, buf.as_mut_ptr() as *mut c_char, &mut size)
};
if status == 0 {
LicenseError::Success
} else {
LicenseError::from_bit_status(status)
}
});
match result {
Some(err) => to_craft_result(err),
None => to_craft_result(LicenseError::WrongHandle),
}
}
```
- [ ] **Step 2: 在 ffi/mod.rs 中注册 bridge**
`native/craft-core/src/ffi/mod.rs` 添加:
```rust
pub mod bridge;
```
- [ ] **Step 3: 编译验证**
```bash
cargo build --manifest-path native/craft-core/Cargo.toml
```
Expected: 编译成功。
- [ ] **Step 4: 提交**
```bash
git add native/craft-core/src/ffi/bridge.rs native/craft-core/src/ffi/mod.rs
git commit -m "feat(native): add craft_* to Bit_* bridge functions"
```
---
### Task 5: Rust — 重构 lib.rs 使用 session-based 句柄管理
**Files:**
- Modify: `native/craft-core/src/lib.rs`
- [ ] **Step 1: 重写 lib.rs**
用以下内容覆写 `native/craft-core/src/lib.rs`
```rust
// CraftLabs 授权核心库 — Rust 实现
// 导出 C ABI 接口,基于 session 管理,对接 BitAnswer C API
// 对齐 docs/平台架构思路.md §3.1
use std::ffi::CStr;
use std::os::raw::c_char;
use std::ptr;
mod activate;
mod error;
mod ffi;
mod heartbeat;
mod license;
mod security;
mod session;
/// Java long 别名 — session_id
type SessionId = i64;
#[repr(C)]
pub struct CraftResult {
pub success: i32,
pub message: *const c_char,
}
#[repr(C)]
pub struct LicenseInfo {
pub is_licensed: i32,
pub expiration_date: i64,
pub feature_names: *const *const c_char,
pub feature_values: *const i32,
pub feature_count: i32,
}
unsafe fn c_str_to_string(ptr: *const c_char) -> String {
if ptr.is_null() {
String::new()
} else {
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
}
static OK_MSG: &[u8] = b"ok\0";
static FAIL_MSG: &[u8] = b"failure\0";
fn ok_result() -> CraftResult {
CraftResult { success: 1, message: OK_MSG.as_ptr() as *const c_char }
}
fn fail_result() -> CraftResult {
CraftResult { success: 0, message: FAIL_MSG.as_ptr() as *const c_char }
}
// ── 现有 9 个 C ABI 函数(签名不变,内部改为 session 管理)──
#[no_mangle]
pub extern "C" fn craft_initialize(config_json: *const c_char) -> SessionId {
let config = unsafe { c_str_to_string(config_json) };
#[cfg(feature = "security-hardening")]
{
security::anti_debug::anti_debug_check();
let _ = security::integrity::integrity_check();
}
// 注册 session,返回 session_id
session::register_session(config, Vec::new())
}
#[no_mangle]
pub extern "C" fn craft_activate(
session_id: SessionId,
license_key: *const c_char,
_config_json: *const c_char,
) -> CraftResult {
if session_id == 0 { return fail_result(); }
let key = unsafe { c_str_to_string(license_key) };
ffi::bridge::bridge_activate(session_id, &key)
}
#[no_mangle]
pub extern "C" fn craft_check_license(session_id: SessionId) -> CraftResult {
if session_id == 0 { return fail_result(); }
ffi::bridge::bridge_check_license(session_id)
}
#[no_mangle]
pub extern "C" fn craft_get_license_info(session_id: SessionId) -> *mut LicenseInfo {
if session_id == 0 { return ptr::null_mut(); }
license::get_license_info_stub()
}
#[no_mangle]
pub extern "C" fn craft_free_license_info(info: *mut LicenseInfo) {
if !info.is_null() {
unsafe { drop(Box::from_raw(info)); }
}
}
#[no_mangle]
pub extern "C" fn craft_has_feature(
session_id: SessionId,
feature_name: *const c_char,
) -> i32 {
if session_id == 0 { return 0; }
let name = unsafe { c_str_to_string(feature_name) };
// Phase 1: 仍返回 1(桩);Phase 2 对接 Bit_ReadFeature
if license::has_feature_stub(&name) { 1 } else { 0 }
}
#[no_mangle]
pub extern "C" fn craft_release(session_id: SessionId) -> CraftResult {
if session_id == 0 { return fail_result(); }
ffi::bridge::bridge_logout(session_id)
}
#[no_mangle]
pub extern "C" fn craft_heartbeat(session_id: SessionId) -> CraftResult {
if session_id == 0 { return fail_result(); }
ffi::bridge::bridge_heartbeat(session_id)
}
#[no_mangle]
pub extern "C" fn craft_destroy(session_id: SessionId) {
if session_id != 0 {
// 如果还登录着,先 logout
let _ = ffi::bridge::bridge_logout(session_id);
session::remove_session(session_id);
}
}
```
- [ ] **Step 2: 更新 license.rs — 适配新签名**
覆写 `native/craft-core/src/license.rs`
```rust
// License state management — Phase 1 stubs
use crate::LicenseInfo;
use std::ptr;
pub fn get_license_info_stub() -> *mut LicenseInfo {
let info = Box::new(LicenseInfo {
is_licensed: 1,
expiration_date: 0,
feature_names: ptr::null(),
feature_values: ptr::null(),
feature_count: 0,
});
Box::into_raw(info)
}
pub fn has_feature_stub(_feature_name: &str) -> bool {
true
}
```
- [ ] **Step 3: 更新 activate.rs — Phase 1 清空**
覆写 `native/craft-core/src/activate.rs`
```rust
// Activation logic — Phase 1: 使用 ffi::bridge::bridge_activate
// 文件保留用于后续 Phase 扩展
```
- [ ] **Step 4: 编译验证**
```bash
cargo build --manifest-path native/craft-core/Cargo.toml
```
Expected: 编译成功,无 warning。
- [ ] **Step 5: 提交**
```bash
git add native/craft-core/src/lib.rs native/craft-core/src/license.rs native/craft-core/src/activate.rs
git commit -m "refactor(native): switch to session-based handle management in lib.rs"
```
---
### Task 6: Java — 标记 AuthProvider 为 @Deprecated
**Files:**
- Modify: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/AuthProvider.java`
- [ ] **Step 1: 添加 @Deprecated 注解**
`AuthProvider` 接口声明前添加:
```java
@Deprecated(since = "1.1.0", forRemoval = true)
```
完整修改(在第 15 行 `public interface AuthProvider` 前插入):
`native/craft-core/src/activate.rs` 不需要修改,直接修改 Java 文件。
`/Users/huangping/Documents/workspace/craftlabs-authorization-sdk/java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/AuthProvider.java` 第 14 行(`public interface AuthProvider extends AutoCloseable {` 上方)插入 `@Deprecated`
```java
/**
* 授权能力的统一契约:初始化、激活、校验许可、查询特性与释放等生命周期方法。
* ...
* @deprecated 自 1.1.0 起,请使用 {@link cn.craftlabs.auth.CraftLicense} 及其
* {@link cn.craftlabs.auth.session.LicenseSession} 替代。
* 将在 Phase 4 移除。
*/
@Deprecated(since = "1.1.0", forRemoval = true)
public interface AuthProvider extends AutoCloseable {
```
- [ ] **Step 2: 编译验证**
```bash
mvn -f java/pom.xml -pl craftlabs-auth-core -am compile
```
Expected: 编译成功(有 deprecated warning 是预期行为)。
- [ ] **Step 3: 提交**
```bash
git add java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/AuthProvider.java
git commit -m "deprecate: mark AuthProvider as @Deprecated, guide to CraftLicense"
```
---
### Task 7: Java — 创建 6 个能力接口
**Files:**
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseLifecycle.java`
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/FeatureManagement.java`
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/DataItemStore.java`
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseInfoQuery.java`
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/CheckoutManager.java`
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseUtility.java`
- [ ] **Step 1: 创建 LicenseLifecycle**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseLifecycle.java`
```java
package cn.craftlabs.auth.session;
import cn.craftlabs.auth.AuthResult;
/**
* 认证与会话生命周期接口,对齐 BitAnswer C API 的 Login/Logout/Revoke 等。
*
* @since 1.1.0
*/
public interface LicenseLifecycle {
/** 在线激活/更新授权。对应 {@code Bit_UpdateOnline}。 */
AuthResult activate(String licenseKey);
/** 登录授权。对应 {@code Bit_Login}。 */
AuthResult login(String sn, int mode);
/** 特征登录。对应 {@code Bit_LoginEx}。 */
AuthResult loginEx(String sn, int featureId, String reserved, int mode);
/** Token 登录。对应 {@code Bit_LoginByToken}。 */
AuthResult loginByToken(String accessToken);
/** 登出。对应 {@code Bit_Logout}。 */
AuthResult logout();
/** 撤销授权。对应 {@code Bit_Revoke}。 */
AuthResult revoke(String sn);
/** 删除本机 SN 数据。对应 {@code Bit_RemoveSn}。 */
void removeSn(String sn);
/** 手动心跳。对应 {@code Bit_Heartbeat}。 */
AuthResult heartbeat();
/** 释放许可占用。对应 {@code Bit_Logout} + 资源清理。 */
AuthResult release();
}
```
- [ ] **Step 2: 创建 FeatureManagement**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/FeatureManagement.java`
```java
package cn.craftlabs.auth.session;
/**
* 特征项管理接口,对齐 BitAnswer C API 的特征读写/加解密/占用释放。
*
* @since 1.1.0
*/
public interface FeatureManagement {
/** 读取特征值。对应 {@code Bit_ReadFeature}。 */
int readFeature(int featureId);
/** 写入特征值。对应 {@code Bit_WriteFeature}。 */
void writeFeature(int featureId, int value);
/** 查询特征可用量。对应 {@code Bit_QueryFeature}。 */
int queryFeature(int featureId);
/** 释放特征占用。对应 {@code Bit_ReleaseFeature}。 */
int releaseFeature(int featureId);
}
```
- [ ] **Step 3: 创建 DataItemStore**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/DataItemStore.java`
```java
package cn.craftlabs.auth.session;
/**
* 配置项(Data Item)存储接口,对齐 BitAnswer C API 的 Set/Get/Remove/Enum。
*
* @since 1.1.0
*/
public interface DataItemStore {
/** 设置配置项。对应 {@code Bit_SetDataItem}。 */
void setDataItem(String name, byte[] value);
/** 读取配置项。对应 {@code Bit_GetDataItem}。 */
byte[] getDataItem(String name);
/** 删除配置项。对应 {@code Bit_RemoveDataItem}。 */
void removeDataItem(String name);
/** 获取配置项数量。对应 {@code Bit_GetDataItemNum}。 */
int getDataItemCount();
/** 按索引获取配置项名称。对应 {@code Bit_GetDataItemName}。 */
String getDataItemName(int index);
}
```
- [ ] **Step 4: 创建 LicenseInfoQuery**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseInfoQuery.java`
```java
package cn.craftlabs.auth.session;
import cn.craftlabs.auth.LicenseInfo;
/**
* 许可信息查询接口,对齐 BitAnswer C API 的 GetSessionInfo/GetInfo/GetServerInfo。
*
* @since 1.1.0
*/
public interface LicenseInfoQuery {
/** 获取许可快照。对应 {@code Bit_GetInfo(BIT_INFO_SN)}。 */
LicenseInfo getLicenseInfo();
/** 获取会话信息。对应 {@code Bit_GetSessionInfo}。 */
String getSessionInfo(int sessionType);
/** 获取授权详情。对应 {@code Bit_GetInfo}。 */
String getInfo(int infoType);
}
```
- [ ] **Step 5: 创建 CheckoutManager**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/CheckoutManager.java`
```java
package cn.craftlabs.auth.session;
/**
* 浮动授权借出/归还接口,对齐 BitAnswer C API 的 CheckOut/CheckIn 系列。
*
* @since 1.1.0
*/
public interface CheckoutManager {
/** 浮动迁出 SN。对应 {@code Bit_CheckOutSn}。 */
void checkOutSn(String url, int featureId, int durationDays);
/** 浮动归还。对应 {@code Bit_CheckIn}。 */
void checkIn(String url, int featureId);
}
```
- [ ] **Step 6: 创建 LicenseUtility**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseUtility.java`
```java
package cn.craftlabs.auth.session;
/**
* 工具方法接口,对齐 BitAnswer C API 的 SetAttr/CustomInfo/Version 等。
*
* @since 1.1.0
*/
public interface LicenseUtility {
/** 设置句柄属性。对应 {@code Bit_SetAttr}。 */
void setAttr(int type, byte[] value);
/** 获取库版本。对应 {@code Bit_GetVersion}。 */
int getVersion();
/** 获取上一次错误码。对应 {@code Bit_GetLastError}。 */
int getLastError();
}
```
- [ ] **Step 7: 编译验证**
```bash
mvn -f java/pom.xml -pl craftlabs-auth-core -am compile
```
Expected: 编译成功。
- [ ] **Step 8: 提交**
```bash
git add java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/
git commit -m "feat(java): add 6 capability interfaces for BitAnswer 1:1 mapping"
```
---
### Task 8: Java — 创建 LicenseSession(骨架实现 6 个接口)
**Files:**
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseSession.java`
- [ ] **Step 1: 创建 LicenseSession**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseSession.java`
```java
package cn.craftlabs.auth.session;
import cn.craftlabs.auth.AuthResult;
import cn.craftlabs.auth.LicenseInfo;
import cn.craftlabs.auth.internal.NativeBridge;
/**
* 授权会话,实现 6 个能力接口。
* Phase 1: 仅实现 AuthProvider 兼容方法(委托 NativeBridge),
* 其他能力接口方法为骨架(返回默认值或抛出 UnsupportedOperationException)。
*
* @since 1.1.0
*/
public final class LicenseSession
implements LicenseLifecycle, FeatureManagement, DataItemStore,
LicenseInfoQuery, CheckoutManager, LicenseUtility, AutoCloseable {
private final long sessionId;
private boolean closed;
LicenseSession(long sessionId) {
this.sessionId = sessionId;
this.closed = false;
}
long getSessionId() { return sessionId; }
// ── LicenseLifecycle ──
@Override public AuthResult activate(String licenseKey) {
ensureOpen();
return NativeBridge.nativeActivate(sessionId, licenseKey);
}
@Override public AuthResult login(String sn, int mode) {
ensureOpen();
return NativeBridge.nativeLogin(sessionId, sn, mode);
}
@Override public AuthResult loginEx(String sn, int featureId, String reserved, int mode) {
ensureOpen();
return NativeBridge.nativeLoginEx(sessionId, sn, featureId, reserved, mode);
}
@Override public AuthResult loginByToken(String accessToken) {
ensureOpen();
return NativeBridge.nativeLoginByToken(sessionId, accessToken);
}
@Override public AuthResult logout() {
ensureOpen();
return NativeBridge.nativeLogout(sessionId);
}
@Override public AuthResult revoke(String sn) {
ensureOpen();
return NativeBridge.nativeRevoke(sessionId, sn);
}
@Override public void removeSn(String sn) {
ensureOpen();
NativeBridge.nativeRemoveSn(sessionId, sn);
}
@Override public AuthResult heartbeat() {
ensureOpen();
return NativeBridge.nativeHeartbeat(sessionId);
}
@Override public AuthResult release() {
ensureOpen();
return NativeBridge.nativeRelease(sessionId);
}
// ── FeatureManagement ──
@Override public int readFeature(int featureId) {
ensureOpen();
return NativeBridge.nativeReadFeature(sessionId, featureId);
}
@Override public void writeFeature(int featureId, int value) {
ensureOpen();
NativeBridge.nativeWriteFeature(sessionId, featureId, value);
}
@Override public int queryFeature(int featureId) {
ensureOpen();
return NativeBridge.nativeQueryFeature(sessionId, featureId);
}
@Override public int releaseFeature(int featureId) {
ensureOpen();
return NativeBridge.nativeReleaseFeature(sessionId, featureId);
}
// ── DataItemStore ──
@Override public void setDataItem(String name, byte[] value) {
ensureOpen();
NativeBridge.nativeSetDataItem(sessionId, name, value);
}
@Override public byte[] getDataItem(String name) {
ensureOpen();
return NativeBridge.nativeGetDataItem(sessionId, name);
}
@Override public void removeDataItem(String name) {
ensureOpen();
NativeBridge.nativeRemoveDataItem(sessionId, name);
}
@Override public int getDataItemCount() {
ensureOpen();
return NativeBridge.nativeGetDataItemNum(sessionId);
}
@Override public String getDataItemName(int index) {
ensureOpen();
return NativeBridge.nativeGetDataItemName(sessionId, index);
}
// ── LicenseInfoQuery ──
@Override public LicenseInfo getLicenseInfo() {
ensureOpen();
return NativeBridge.nativeGetLicenseInfo(sessionId);
}
@Override public String getSessionInfo(int sessionType) {
ensureOpen();
return NativeBridge.nativeGetSessionInfo(sessionId, sessionType);
}
@Override public String getInfo(int infoType) {
ensureOpen();
return NativeBridge.nativeGetInfo(sessionId, infoType);
}
// ── CheckoutManager ──
@Override public void checkOutSn(String url, int featureId, int durationDays) {
ensureOpen();
NativeBridge.nativeCheckOutSn(sessionId, url, featureId, durationDays);
}
@Override public void checkIn(String url, int featureId) {
ensureOpen();
NativeBridge.nativeCheckIn(sessionId, url, featureId);
}
// ── LicenseUtility ──
@Override public void setAttr(int type, byte[] value) {
ensureOpen();
NativeBridge.nativeSetAttr(sessionId, type, value);
}
@Override public int getVersion() {
return NativeBridge.nativeGetVersion();
}
@Override public int getLastError() {
ensureOpen();
return NativeBridge.nativeGetLastError(sessionId);
}
// ── Lifecycle ──
@Override public void close() {
if (!closed) {
NativeBridge.nativeDestroy(sessionId);
closed = true;
}
}
public boolean isClosed() { return closed; }
private void ensureOpen() {
if (closed) throw new IllegalStateException("Session is closed");
}
}
```
- [ ] **Step 2: 编译验证(预期失败 — NativeBridge 缺少新方法)**
```bash
mvn -f java/pom.xml -pl craftlabs-auth-core -am compile 2>&1 | head -30
```
Expected: 编译失败,提示 `NativeBridge` 缺少 `nativeLogin``nativeLogout` 等方法。
- [ ] **Step 3: 提交**
```bash
git add java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/session/LicenseSession.java
git commit -m "feat(java): add LicenseSession skeleton implementing 6 capability interfaces"
```
---
### Task 9: Java — 扩展 NativeBridge(添加 Phase 1 新 JNI 方法)
**Files:**
- Modify: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/internal/NativeBridge.java`
- [ ] **Step 1: 在 NativeBridge 中添加所有新 native 方法声明**
在现有方法后追加:
```java
// ── Phase 1 新增:会话/认证 ──
public static native AuthResult nativeLogin(long handle, String sn, int mode);
public static native AuthResult nativeLoginEx(long handle, String sn, int featureId, String reserved, int mode);
public static native AuthResult nativeLoginByToken(long handle, String accessToken);
public static native AuthResult nativeLogout(long handle);
// ── Phase 1 新增:特征项 ──
public static native int nativeReadFeature(long handle, int featureId);
public static native void nativeWriteFeature(long handle, int featureId, int value);
public static native int nativeQueryFeature(long handle, int featureId);
public static native int nativeReleaseFeature(long handle, int featureId);
// ── Phase 1 新增:配置项 ──
public static native void nativeSetDataItem(long handle, String name, byte[] value);
public static native byte[] nativeGetDataItem(long handle, String name);
public static native void nativeRemoveDataItem(long handle, String name);
public static native int nativeGetDataItemNum(long handle);
public static native String nativeGetDataItemName(long handle, int index);
// ── Phase 1 新增:信息查询 ──
public static native String nativeGetSessionInfo(long handle, int sessionType);
public static native String nativeGetInfo(long handle, int infoType);
// ── Phase 1 新增:浮动授权 ──
public static native void nativeCheckOutSn(long handle, String url, int featureId, int durationDays);
public static native void nativeCheckIn(long handle, String url, int featureId);
// ── Phase 1 新增:撤销/删除 ──
public static native AuthResult nativeRevoke(long handle, String sn);
public static native void nativeRemoveSn(long handle, String sn);
// ── Phase 1 新增:工具 ──
public static native void nativeSetAttr(long handle, int type, byte[] value);
public static native int nativeGetVersion();
public static native int nativeGetLastError(long handle);
```
- [ ] **Step 2: 编译验证**
```bash
mvn -f java/pom.xml -pl craftlabs-auth-core -am compile
```
Expected: 编译成功(native 方法声明不要求立即有 JNI 实现,运行时才链接)。
- [ ] **Step 3: 提交**
```bash
git add java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/internal/NativeBridge.java
git commit -m "feat(java): extend NativeBridge with Phase 1 JNI method declarations (30+ new methods)"
```
---
### Task 10: Java — 创建 CraftLicense(新顶层入口)
**Files:**
- Create: `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/CraftLicense.java`
- [ ] **Step 1: 创建 CraftLicense**
写入 `java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/CraftLicense.java`
```java
package cn.craftlabs.auth;
import cn.craftlabs.auth.internal.NativeBridge;
import cn.craftlabs.auth.session.LicenseSession;
/**
* CraftLabs 授权 SDK 的顶层入口,替代 {@link AuthProvider}。
*
* <p>用法:
* <pre>{@code
* CraftLicense license = new CraftLicense();
* try (LicenseSession session = license.initialize("{\"schemaVersion\":1,...}")) {
* session.activate("SN-XXXX");
* int val = session.readFeature(1);
* }
* }</pre>
*
* @since 1.1.0
*/
public final class CraftLicense {
static {
System.loadLibrary("craftlabs_auth_bitanswer");
}
/**
* 使用 JSON 配置初始化授权会话。
*
* @param configJson 符合 {@code schemas/craftlabs-auth-config.schema.json} 的配置字符串
* @return 新的 {@link LicenseSession}
*/
public LicenseSession initialize(String configJson) {
String cfg = configJson != null ? configJson : "{}";
long sessionId = NativeBridge.nativeInitialize(cfg);
return new LicenseSession(sessionId);
}
}
```
- [ ] **Step 2: 编译验证**
```bash
mvn -f java/pom.xml -pl craftlabs-auth-core -am compile
```
Expected: 编译成功。
- [ ] **Step 3: 提交**
```bash
git add java/craftlabs-auth-core/src/main/java/cn/craftlabs/auth/CraftLicense.java
git commit -m "feat(java): add CraftLicense as new entry point replacing AuthProvider"
```
---
### Task 11: Java — 运行现有测试确保没有回归
**Files:**
- (验证,不修改)
- 测试文件: `java/craftlabs-auth-tests/src/test/java/cn/craftlabs/auth/BitAnswerProviderTest.java`
- [ ] **Step 1: 运行现有 Java SDK 测试**
```bash
mvn -f java/pom.xml -B verify
```
Expected: 现有测试通过(`AuthProvider` 未移除,桩行为不变)。
- [ ] **Step 2: 验证 deprecated 警告存在但不为 error**
Expected: 编译输出包含 `AuthProvider is deprecated` 警告,但不阻止构建。
- [ ] **Step 3: 提交**
```bash
git add -A
git commit -m "verify: existing tests pass after Phase 1 refactor — no regression"
```
---
### Task 12: Rust — 编译验证并确保 C ABI 兼容
**Files:**
- (验证,不修改)
- [ ] **Step 1: 编译 Rust debug**
```bash
cargo build --manifest-path native/craft-core/Cargo.toml
```
Expected: 编译成功。
- [ ] **Step 2: 编译 Rust release**
```bash
cargo build --manifest-path native/craft-core/Cargo.toml --release
```
Expected: 编译成功。产物位于 `native/target/release/libcraftlabs_auth_bitanswer.{so,dylib}`
- [ ] **Step 3: 验证 C ABI 符号导出**
```bash
nm native/target/debug/libcraftlabs_auth_bitanswer.dylib 2>/dev/null | grep " T _craft_" || \
nm native/target/debug/libcraftlabs_auth_bitanswer.so 2>/dev/null | grep " T craft_" || \
echo "Check platform-specific symbol listing"
```
Expected: 输出包含 `craft_initialize``craft_activate``craft_heartbeat` 等符号。
---
## Phase 1 完成检查点
Phase 1 完成后:
- ✅ Rust: error.rs、session.rs、ffi/bitanswer.rs、ffi/bridge.rs 已创建
- ✅ Rust: lib.rs 重构为 session-based 句柄管理
- ✅ Rust: 现有 9 个 C ABI 函数签名不变,内部桥接到 BitAnswer
- ✅ Java: AuthProvider 标记 @Deprecated
- ✅ Java: 6 个能力接口已定义
- ✅ Java: LicenseSession 骨架实现
- ✅ Java: NativeBridge 新增 30+ JNI 方法声明
- ✅ Java: CraftLicense 新入口已创建
- ✅ 现有测试通过,无回归
---
## Phase 2 — 核心 API 扩展
> Phase 2 任务在 Phase 1 通过后执行,将骨架实现替换为真实调用。
### Task 13: Rust — 扩展 activate.rs、heartbeat.rs、license.rs 为真实调用
- [ ] 实现 `craft_login` C ABI 函数(对接 `bridge_login`
- [ ] 实现 `craft_login_ex` C ABI 函数(对接 `Bit_LoginEx`
- [ ] 实现 `craft_revoke` C ABI 函数(对接 `Bit_Revoke`
- [ ] 实现 `craft_remove_sn` C ABI 函数(对接 `Bit_RemoveSn`
- [ ] 实现 `craft_read_feature` C ABI 函数(对接 `Bit_ReadFeature`
- [ ] 实现 `craft_write_feature` C ABI 函数(对接 `Bit_WriteFeature`
- [ ] 实现 `craft_query_feature` C ABI 函数(对接 `Bit_QueryFeature`
- [ ] 实现 `craft_release_feature` C ABI 函数(对接 `Bit_ReleaseFeature`
- [ ] 每个函数添加 Rust 单元测试(mock BitAnswer extern
- [ ] 编译验证:`cargo test --manifest-path native/craft-core/Cargo.toml`
### Task 14: Java — BitAnswerProvider 委托到 LicenseSession
- [ ] 修改 `BitAnswerProvider``initialize` 使用 `CraftLicense`
- [ ] 保留 `AuthProvider` 接口兼容性
- [ ] 编译验证:`mvn -f java/pom.xml -B verify`
---
## Phase 3 — 高级功能
### Task 15: Rust — DataItem + Checkout 桥接
- [ ] 实现 `craft_set_data_item` / `craft_get_data_item` / `craft_remove_data_item`
- [ ] 实现 `craft_check_out_sn` / `craft_check_in`
- [ ] 实现离线升级流程(`GetRequestInfo``GetUpdateInfo``ApplyUpdateInfo`
### Task 16: Java — DataItemStore + CheckoutManager 完整实现
- [ ] `DataItemStore` 方法全部对接 NativeBridge
- [ ] `CheckoutManager` 方法全部对接 NativeBridge
- [ ] 添加集成测试
---
## Phase 4 — 清理
### Task 17: 移除废弃代码
- [ ] 删除 `AuthProvider` 接口
- [ ] 删除 `.deprecated-cmake/` 目录
- [ ] 更新 `BitAnswerProvider` 以在新接口下工作(或标记废弃)
- [ ] 全量回归:`mvn -f java/pom.xml -B verify && cargo test`
```
(Plan too long; 668 lines exceeds maximum 500 lines set in preferences. You are seeing the truncated version (500 lines). To see the full plan, read the file /Users/huangping/Documents/workspace/craftlabs-authorization-sdk/docs/superpowers/plans/2026-05-01-bitanswer-1to1-refactor.md directly. Lines 501-668 were not written.)<end▁of▁thinking>文件被截断了。让我确认完整写入:
<||DSML||tool_calls>
<||DSML||invoke name="bash">
<||DSML||parameter name="description" string="true">Check plan file line count