Commit cf74440a777fcd4bb95f147453b723f57a56025a

Authored by 权海
1 parent 72cf904b

feat(ui):增加app路由跳转传递给flutter, 完善watch theme; 现在runner iOS工程可以直接调试了

Showing 43 changed files with 4307 additions and 315 deletions

Too many changes to show.

To preserve performance only 43 of 43+ files are displayed.

... ... @@ -307,7 +307,7 @@ interface HealthKitHostApi {
fun getHealthServerAuthUrl(callback: (Result<String>) -> Unit)
fun cancelHealthAppAuthorization(): Boolean
/** Runs native health read and server upload pipeline. */
fun performHealthUpload(): HealthUploadResult
fun performHealthUpload(callback: (Result<HealthUploadResult>) -> Unit)
/** Opens Huawei Health client authorization UI. Returns whether user granted. */
fun checkHealthAppAuthorization(callback: (Result<HealthAuthorization>) -> Unit)
fun requestHealthClientAuthorization(callback: (Result<Boolean>) -> Unit)
... ... @@ -373,12 +373,15 @@ interface HealthKitHostApi {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.performHealthUpload$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
listOf(api.performHealthUpload())
} catch (exception: Throwable) {
HealthKitApiPigeonUtils.wrapError(exception)
api.performHealthUpload{ result: Result<HealthUploadResult> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(HealthKitApiPigeonUtils.wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(HealthKitApiPigeonUtils.wrapResult(data))
}
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
... ...
... ... @@ -359,6 +359,10 @@ interface PlatformHostApi {
fun requestAppReview(callback: (Result<Boolean>) -> Unit)
/** 跳app应用设置:通知、定位等权限 */
fun jumpAppSetting(): Boolean
/** 原生处理跳转url */
fun nativeHandleUrl(urlString: String): Boolean
/** 从原生拿需要处理的url, 主要场景是点击通知跳转 */
fun requestUnhandedUrl(): String?
/** 请求苹果登录 */
fun requestAppleSignIn(callback: (Result<AppleSignInModel?>) -> Unit)
/**
... ... @@ -517,6 +521,38 @@ interface PlatformHostApi {
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.PlatformHostApi.nativeHandleUrl$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val urlStringArg = args[0] as String
val wrapped: List<Any?> = try {
listOf(api.nativeHandleUrl(urlStringArg))
} catch (exception: Throwable) {
PlatformApiPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.PlatformHostApi.requestUnhandedUrl$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
listOf(api.requestUnhandedUrl())
} catch (exception: Throwable) {
PlatformApiPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.PlatformHostApi.requestAppleSignIn$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
... ...
... ... @@ -28,6 +28,7 @@ flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
pod 'OBS', :path => './Runner/Library'
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
... ... @@ -51,6 +52,7 @@ post_install do |installer|
target.build_configurations.each do |config|
config.build_settings['ENABLE_USER_SCRIPT_SANDBOXING'] = 'NO'
config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
end
end
end
... ...
... ... @@ -19,6 +19,7 @@ PODS:
- libwebp/sharpyuv (1.5.0)
- libwebp/webp (1.5.0):
- libwebp/sharpyuv
- OBS (3.20.11.1)
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
... ... @@ -45,6 +46,7 @@ DEPENDENCIES:
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- OBS (from `./Runner/Library`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
... ... @@ -67,6 +69,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/image_cropper/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
OBS:
:path: "./Runner/Library"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
... ... @@ -88,6 +92,7 @@ SPEC CHECKSUMS:
image_cropper: c4326ea50132b1e1564499e5d32a84f01fb03537
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
OBS: 4cf1e6db5515aefd6c3c6ae3e90e85ea5f028e83
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
... ... @@ -97,6 +102,6 @@ SPEC CHECKSUMS:
video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140
webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2
PODFILE CHECKSUM: b9265b4a06e32777ce541c63a22ad629b9ccc6ae
PODFILE CHECKSUM: 9336dec050b93f0e3aeb7daef71d30ec0e2195f3
COCOAPODS: 1.16.2
... ...
... ... @@ -732,6 +732,11 @@
CURRENT_PROJECT_VERSION = 73;
DEVELOPMENT_TEAM = ZRPLMC329K;
ENABLE_PREVIEWS = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Runner/Library",
);
"FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = (
"$(inherited)",
"$(BUILT_PRODUCTS_DIR)",
... ... @@ -806,6 +811,11 @@
CURRENT_PROJECT_VERSION = 73;
DEVELOPMENT_TEAM = ZRPLMC329K;
ENABLE_PREVIEWS = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Runner/Library",
);
"FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = (
"$(inherited)",
"$(BUILT_PRODUCTS_DIR)",
... ...
... ... @@ -14,23 +14,19 @@ import AdSupport
typealias FlutterBridgeMethod = ((_ params: Any?, _ result: FlutterResult) -> Void)
let kAppId = "6747254434"
@Observable
class AppDelegate: NSObject, UIApplicationDelegate {
/// UIApplicationDelegate 要求声明 window,
/// image_cropper 等插件会通过 UIApplication.shared.delegate?.window 查找 keyWindow,
/// 缺少此属性会导致 "unrecognized selector" 崩溃。
var window: UIWindow?
private(set) var enginInitError: String?
enum FlutterBridgeMethodName: String{
case verifyPayment
case handleFlutterUrl
}
private var methods: [String: FlutterBridgeMethod] = [:]
var flutterEngine: FlutterEngine?
var channel: FlutterMethodChannel?
private var isFlutterEngineReady = false
... ... @@ -42,7 +38,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
AppShared.shared.agent.genUA()
AppShared.shared.payment.delegate = self
_ = AppShared.shared.payment.listenForTransactions()
UIApplication.shared.registerForRemoteNotifications()
UNUserNotificationCenter.current().setBadgeCount(0)
UNUserNotificationCenter.current().delegate = self
... ... @@ -50,9 +46,32 @@ class AppDelegate: NSObject, UIApplicationDelegate {
WatchConnectivityService.shared.activate()
HealthKitService.shared.startBackgroundObserversIfNeeded()
cacheLaunchURLIfNeeded(launchOptions)
return true
}
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
handleFlutterUrl(url.absoluteString)
return true
}
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let urlString = userActivity.webpageURL?.absoluteString else {
return false
}
handleFlutterUrl(urlString)
return true
}
func warmUpFlutterEngineIfNeeded() {
guard !isFlutterEngineReady else {
enginInitError = nil
... ... @@ -69,16 +88,18 @@ class AppDelegate: NSObject, UIApplicationDelegate {
NativePigeonRegistrar.register(binaryMessenger: flutterEngine.binaryMessenger)
channel = FlutterMethodChannel(name: "doublefeel_flutter_main_channel", binaryMessenger: flutterEngine.binaryMessenger)
methods = defaultMethods()
enginInitError = nil
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("✅ Device Token: \(token)")
AppGroupConstants.defaults?.set(token, forKey: AppGroupConstants.Key.appDeviceToken)
Task{
await AppShared.shared.reportDeviceInfo()
}
}
func application(_ application: UIApplication,
... ... @@ -90,16 +111,73 @@ class AppDelegate: NSObject, UIApplicationDelegate {
extension AppDelegate{
private func defaultMethods() -> [String: FlutterBridgeMethod]{
var methods: [String: FlutterBridgeMethod] = [:]
methods[FlutterBridgeMethodName.verifyPayment.rawValue] = { params, result in
methods[FlutterBridgeMethodName.handleFlutterUrl.rawValue] = { params, result in
result(params)
}
return methods
}
func invoke(method: FlutterBridgeMethodName, arguments: Any?, result: @escaping FlutterResult){
channel?.invokeMethod(method.rawValue, arguments: arguments, result: result)
}
private func cacheLaunchURLIfNeeded(_ launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
if let url = launchOptions?[.url] as? URL {
AppShared.shared.unhandedUrl = url.absoluteString
return
}
if let userActivityDictionary = launchOptions?[.userActivityDictionary] as? [AnyHashable: Any] {
for value in userActivityDictionary.values {
guard let userActivity = value as? NSUserActivity,
userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let urlString = userActivity.webpageURL?.absoluteString else {
continue
}
AppShared.shared.unhandedUrl = urlString
return
}
}
if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable: Any],
let urlString = Self.flutterURLString(from: userInfo) {
AppShared.shared.unhandedUrl = urlString
}
}
func handleFlutterUrl(_ urlString: String) {
guard !urlString.isEmpty else {
return
}
guard channel != nil else {
AppShared.shared.unhandedUrl = urlString
return
}
invoke(method: .handleFlutterUrl, arguments: [
"url": urlString
]) { result in
if let error = result as? FlutterError {
DebugLogger.log(desc: "handleFlutterUrl error: \(error.message ?? error.code)")
}
}
}
private static func flutterURLString(from userInfo: [AnyHashable: Any]) -> String? {
if let urlString = userInfo["url"] as? String {
return urlString
}
guard let payload = userInfo["payload"] as? String,
let data = payload.data(using: .utf8),
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
return nil
}
return dict["url"] as? String
}
}
extension AppDelegate: UNUserNotificationCenterDelegate{
... ... @@ -108,23 +186,13 @@ extension AppDelegate: UNUserNotificationCenterDelegate{
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .sound, .badge])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// 从通知中获取 URL
if let payload = userInfo["payload"] as? String,
let data = payload.data(using: .utf8),
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let urlString = dict["url"] as? String,
let url = URL(string: urlString) {
// 通过 openURL 触发 onOpenURL 回调
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
}
if let urlString = Self.flutterURLString(from: userInfo) {
handleFlutterUrl(urlString)
}
completionHandler()
}
... ...
//
// AppleHealthTestView.swift
// Runner
//
// Created by 权海 on 2026/6/15.
//
import SwiftUI
struct AppleHealthTestView: View {
@State private var logs: [String] = []
@State private var isRunning = false
@State private var runningTitle: String?
private let api = HealthKitHostApiImpl()
private let logTimeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss.SSS"
return formatter
}()
var body: some View {
NavigationStack {
VStack(spacing: 0) {
logPanel
Divider()
HStack(spacing: 12) {
actionButton(title: "AppleHealth 权限检查", systemImage: "checkmark.shield") {
await runPermissionCheck()
}
actionButton(title: "获取数据接口", systemImage: "waveform.path.ecg") {
await runDataFetch()
}
}
.padding(16)
.background(.regularMaterial)
}
.navigationTitle("Apple Health Test")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("清空") {
logs.removeAll()
}
.disabled(isRunning || logs.isEmpty)
}
}
}
}
private var logPanel: some View {
ScrollViewReader { proxy in
ScrollView {
LazyVStack(alignment: .leading, spacing: 8) {
if logs.isEmpty {
ContentUnavailableView(
"暂无日志",
systemImage: "list.bullet.rectangle",
description: Text("点击底部按钮开始测试 HealthKitHostApiImpl。")
)
.frame(maxWidth: .infinity, minHeight: 280)
} else {
ForEach(Array(logs.enumerated()), id: \.offset) { index, line in
Text(line)
.font(.system(.footnote, design: .monospaced))
.foregroundStyle(line.contains("❌") ? .red : .primary)
.textSelection(.enabled)
.frame(maxWidth: .infinity, alignment: .leading)
.id(index)
}
}
}
.padding(16)
}
.background(Color(.systemGroupedBackground))
.onChange(of: logs.count) { _, newValue in
guard newValue > 0 else { return }
withAnimation(.easeOut(duration: 0.2)) {
proxy.scrollTo(newValue - 1, anchor: .bottom)
}
}
}
}
private func actionButton(
title: String,
systemImage: String,
action: @escaping () async -> Void
) -> some View {
Button {
guard !isRunning else { return }
Task {
await runAction(title, action: action)
}
} label: {
Label(isRunning && runningTitle == title ? "执行中..." : title, systemImage: systemImage)
.font(.system(size: 15, weight: .semibold))
.frame(maxWidth: .infinity)
.frame(height: 48)
}
.buttonStyle(.borderedProminent)
.disabled(isRunning)
}
@MainActor
private func runAction(_ title: String, action: @escaping () async -> Void) async {
isRunning = true
runningTitle = title
appendLog("▶️ \(title) 开始")
await action()
appendLog("✅ \(title) 完成")
isRunning = false
runningTitle = nil
}
private func runPermissionCheck() async {
do {
let authorization = try await checkHealthAuthorization()
appendLog("checkHealthAppAuthorization status=\(authorization.status), hasData=\(authorization.hasData)")
let authUrl = try await getHealthServerAuthUrl()
appendLog("getHealthServerAuthUrl = \(authUrl.isEmpty ? "<empty, iOS system managed>" : authUrl)")
if authorization.status == 0 {
appendLog("当前需要请求授权,开始 requestHealthClientAuthorization")
let granted = try await requestHealthClientAuthorization()
appendLog("requestHealthClientAuthorization = \(granted)")
} else {
appendLog("当前不需要再次请求授权,跳过 requestHealthClientAuthorization")
}
let cancelResult = try api.cancelHealthAppAuthorization()
appendLog("cancelHealthAppAuthorization = \(cancelResult) (iOS 不支持应用内撤销)")
} catch {
appendError("权限检查失败", error)
}
}
private func runDataFetch() async {
let endTime = Int64(Date().timeIntervalSince1970)
let startTime = Int64(Calendar.current.date(byAdding: .day, value: -7, to: Date())?.timeIntervalSince1970 ?? Date().timeIntervalSince1970)
appendLog("数据范围: \(formatTimestamp(startTime)) -> \(formatTimestamp(endTime))")
do {
let uploadResult = try api.performHealthUpload()
appendLog(
"performHealthUpload common=\(uploadResult.commonUploadSuccess), sleep=\(uploadResult.sleepUploadSuccess), error=\(uploadResult.errorMessage ?? "nil")"
)
} catch {
appendError("performHealthUpload 失败", error)
}
await fetchCommon("HRV", startTime, endTime, api.fetchHrvData)
await fetchCommon("心率", startTime, endTime, api.fetchHeartRateData)
await fetchCommon("步行心率", startTime, endTime, api.fetchWalkingHeartRateData)
await fetchCommon("静息心率", startTime, endTime, api.fetchRestingHeartRateData)
await fetchCommon("睡眠心率", startTime, endTime, api.fetchSleepingHeartRateData)
await fetchCommon("血氧", startTime, endTime, api.fetchOxygenSaturationData)
await fetchCommon("活动能量", startTime, endTime, api.fetchActiveEnergyData)
await fetchCommon("锻炼", startTime, endTime, api.fetchExerciseData)
await fetchCommon("站立", startTime, endTime, api.fetchStandData)
await fetchCommon("步数", startTime, endTime, api.fetchStepCountData)
await fetchCommon("睡眠腕温", startTime, endTime, api.fetchSleepingWristTemperatureData)
await fetchCommon("呼吸频率", startTime, endTime, api.fetchRespiratoryRateData)
await fetchCommon("不规则心律", startTime, endTime, api.fetchIrregularHeartRhythmData)
await fetchSleep(startTime: startTime, endTime: endTime)
await fetchActivityTarget(startTime: startTime, endTime: endTime)
}
private func fetchCommon(
_ title: String,
_ startTime: Int64,
_ endTime: Int64,
_ fetch: @escaping (Int64, Int64, @escaping (Result<[HealthUploadDataPoint], Error>) -> Void) -> Void
) async {
do {
let points = try await withCheckedThrowingContinuation { continuation in
fetch(startTime, endTime) { result in
continuation.resume(with: result)
}
}
appendLog("\(title): \(points.count) 条")
appendSample(points)
} catch {
appendError("\(title) 获取失败", error)
}
}
private func fetchSleep(startTime: Int64, endTime: Int64) async {
do {
let points = try await withCheckedThrowingContinuation { continuation in
api.fetchSleepData(startTime: startTime, endTime: endTime) { result in
continuation.resume(with: result)
}
}
appendLog("睡眠: \(points.count) 条")
for point in points.prefix(3) {
appendLog(" sample dataType=\(point.dataType), from=\(formatTimestamp(point.fromTime)), to=\(formatTimestamp(point.toTime))")
}
} catch {
appendError("睡眠获取失败", error)
}
}
private func fetchActivityTarget(startTime: Int64, endTime: Int64) async {
do {
let target = try await withCheckedThrowingContinuation { continuation in
api.fetchActivityTargetData(startTime: startTime, endTime: endTime) { result in
continuation.resume(with: result)
}
}
if let target {
appendLog("活动目标: move=\(target.move.map(String.init) ?? "nil"), stand=\(target.stand.map(String.init) ?? "nil")")
} else {
appendLog("活动目标: nil")
}
} catch {
appendError("活动目标获取失败", error)
}
}
private func checkHealthAuthorization() async throws -> HealthAuthorization {
try await withCheckedThrowingContinuation { continuation in
api.checkHealthAppAuthorization { result in
continuation.resume(with: result)
}
}
}
private func requestHealthClientAuthorization() async throws -> Bool {
try await withCheckedThrowingContinuation { continuation in
api.requestHealthClientAuthorization { result in
continuation.resume(with: result)
}
}
}
private func getHealthServerAuthUrl() async throws -> String {
try await withCheckedThrowingContinuation { continuation in
api.getHealthServerAuthUrl { result in
continuation.resume(with: result)
}
}
}
@MainActor
private func appendLog(_ message: String) {
logs.append("[\(logTimeFormatter.string(from: Date()))] \(message)")
}
@MainActor
private func appendError(_ prefix: String, _ error: Error) {
appendLog("❌ \(prefix): \(error.localizedDescription)")
}
@MainActor
private func appendSample(_ points: [HealthUploadDataPoint]) {
for point in points.prefix(3) {
appendLog(" sample dataType=\(point.dataType), time=\(formatTimestamp(point.time)), value=\(point.value)")
}
}
private func formatTimestamp(_ timestamp: Int64) -> String {
let date = Date(timeIntervalSince1970: TimeInterval(timestamp))
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return formatter.string(from: date)
}
}
#Preview {
AppleHealthTestView()
}
import Foundation
struct NativeHealthUploadSummary {
let commonUploadSuccess: Bool
let sleepUploadSuccess: Bool
let errorMessage: String?
let commonCount: Int
let sleepCount: Int
}
enum NativeHealthUploadError: LocalizedError {
case invalidServerURL
case missingAccessToken
case invalidResponse
case requestFailed(path: String, statusCode: Int, body: String?)
var errorDescription: String? {
switch self {
case .invalidServerURL:
return "健康数据上传地址无效"
case .missingAccessToken:
return "缺少登录态,无法上传健康数据"
case .invalidResponse:
return "健康数据上传接口响应无效"
case .requestFailed(let path, let statusCode, let body):
return "健康数据接口请求失败:\(path), HTTP \(statusCode)\(body.map { ", \($0)" } ?? "")"
}
}
}
/// Uploads Apple Health data to DoubleFeel.
///
/// Data reading stays in `HealthDataReader` / `HealthKitService`; this type only
/// owns upload requests and the per-user last-upload-time cache migrated from
/// the original SwiftUI app.
final class NativeHealthDataUploader {
static let shared = NativeHealthDataUploader()
private let session: URLSession
private var uploadTimeRecorder: NativeHealthUploadTimeRecorder
private let maxUploadTimeWeek = 4
private let defaultUploadTimeWeek = 1
private let firstUploadYear = 2
init(
session: URLSession = .shared,
uploadTimeRecorder: NativeHealthUploadTimeRecorder = NativeHealthUploadTimeRecorder()
) {
self.session = session
self.uploadTimeRecorder = uploadTimeRecorder
}
func uploadAll(service: HealthKitService = .shared) async -> NativeHealthUploadSummary {
var commonCount = 0
var sleepCount = 0
var commonUploadSuccess = true
var sleepUploadSuccess = true
var errorMessages: [String] = []
debugLog("uploadAll started, userId=\(AppShared.shared.userId ?? "<nil>")")
do {
let uploadTimeList = try await processLastUploadTime()
for type in Self.commonUploadTypes {
let result = await upload(type: type, uploadTimeList: uploadTimeList, service: service)
commonCount += result.uploadedCount
if !result.success {
commonUploadSuccess = false
if let errorMessage = result.errorMessage {
errorMessages.append(errorMessage)
}
}
}
let sleepResult = await upload(type: .sleep, uploadTimeList: uploadTimeList, service: service)
sleepCount = sleepResult.uploadedCount
sleepUploadSuccess = sleepResult.success
if let errorMessage = sleepResult.errorMessage {
errorMessages.append(errorMessage)
}
let activityTargetUploaded = await uploadActivityTargetIfNeeded(
uploadTimeList: uploadTimeList,
service: service
)
if !activityTargetUploaded.success {
commonUploadSuccess = false
if let errorMessage = activityTargetUploaded.errorMessage {
errorMessages.append(errorMessage)
}
}
} catch {
commonUploadSuccess = false
sleepUploadSuccess = false
errorMessages.append(error.localizedDescription)
debugLog("uploadAll failed before per-type upload, error=\(error.localizedDescription)")
}
debugLog("uploadAll finished, commonSuccess=\(commonUploadSuccess), sleepSuccess=\(sleepUploadSuccess), commonCount=\(commonCount), sleepCount=\(sleepCount), error=\(errorMessages.isEmpty ? "<nil>" : errorMessages.joined(separator: " | "))")
return NativeHealthUploadSummary(
commonUploadSuccess: commonUploadSuccess,
sleepUploadSuccess: sleepUploadSuccess,
errorMessage: errorMessages.isEmpty ? nil : errorMessages.joined(separator: "\n"),
commonCount: commonCount,
sleepCount: sleepCount
)
}
func upload(type: NativeHealthDataType, service: HealthKitService = .shared) async -> Bool {
do {
let uploadTimeList = try await processLastUploadTime()
return await upload(type: type, uploadTimeList: uploadTimeList, service: service).success
} catch {
debugLog("upload(\(type.debugName)) failed to process last upload time, error=\(error.localizedDescription)")
print("Health upload failed to process last upload time: \(error.localizedDescription)")
return false
}
}
}
private extension NativeHealthDataUploader {
struct UploadTaskResult {
let success: Bool
let uploadedCount: Int
let errorMessage: String?
}
static let commonUploadTypes: [NativeHealthDataType] = [
.hrv,
.heartRate,
.walkingHeartRate,
.restingHeartRate,
.sleepingHeartRate,
.oxygenSaturation,
.activeEnergy,
.exercise,
.stand,
.steps,
.sleepingWristTemperature,
.respiratoryRate,
.irregularHeartRhythm,
]
func upload(
type: NativeHealthDataType,
uploadTimeList: NativeHealthUploadTimeList,
service: HealthKitService
) async -> UploadTaskResult {
guard type != .unknown,
let startUploadDate = uploadTimeList.latestDataTime(for: type) else {
debugLog("[\(type.debugName)] skipped, no upload start date")
return UploadTaskResult(success: true, uploadedCount: 0, errorMessage: nil)
}
let endUploadDate = Date()
debugLog(
"[\(type.debugName)] upload started, range=\(Self.debugDateFormatter.string(from: startUploadDate)) -> \(Self.debugDateFormatter.string(from: endUploadDate))"
)
guard endUploadDate >= startUploadDate else {
debugLog("[\(type.debugName)] upload failed, start date is later than end date")
return UploadTaskResult(
success: false,
uploadedCount: 0,
errorMessage: "健康数据上传开始时间晚于结束时间:\(type)"
)
}
do {
switch type {
case .sleep:
debugLog("[\(type.debugName)] reading sleep data")
let data = try await service.fetchSleepData(startDate: startUploadDate, endDate: endUploadDate)
debugLog("[\(type.debugName)] read finished, count=\(data.count)")
guard !data.isEmpty else {
uploadTimeRecorder.save(date: endUploadDate, for: type)
debugLog("[\(type.debugName)] no data, saved upload time=\(Self.debugDateFormatter.string(from: endUploadDate))")
return UploadTaskResult(success: true, uploadedCount: 0, errorMessage: nil)
}
debugLog("[\(type.debugName)] uploading, count=\(data.count)")
try await uploadSleep(data)
uploadTimeRecorder.save(date: endUploadDate, for: type)
debugLog("[\(type.debugName)] upload success, count=\(data.count), saved upload time=\(Self.debugDateFormatter.string(from: endUploadDate))")
return UploadTaskResult(success: true, uploadedCount: data.count, errorMessage: nil)
default:
debugLog("[\(type.debugName)] reading common data")
let data = try await fetchCommonData(
type: type,
startDate: startUploadDate,
endDate: endUploadDate,
service: service
)
debugLog("[\(type.debugName)] read finished, count=\(data.count)")
guard !data.isEmpty else {
uploadTimeRecorder.save(date: endUploadDate, for: type)
debugLog("[\(type.debugName)] no data, saved upload time=\(Self.debugDateFormatter.string(from: endUploadDate))")
return UploadTaskResult(success: true, uploadedCount: 0, errorMessage: nil)
}
debugLog("[\(type.debugName)] uploading, count=\(data.count)")
try await uploadCommon(data)
uploadTimeRecorder.save(date: endUploadDate, for: type)
debugLog("[\(type.debugName)] upload success, count=\(data.count), saved upload time=\(Self.debugDateFormatter.string(from: endUploadDate))")
return UploadTaskResult(success: true, uploadedCount: data.count, errorMessage: nil)
}
} catch {
debugLog("[\(type.debugName)] upload failed, error=\(error.localizedDescription)")
return UploadTaskResult(
success: false,
uploadedCount: 0,
errorMessage: "健康数据上传失败:\(type), \(error.localizedDescription)"
)
}
}
func fetchCommonData(
type: NativeHealthDataType,
startDate: Date,
endDate: Date,
service: HealthKitService
) async throws -> [NativeHealthDataPoint] {
switch type {
case .hrv:
return try await service.fetchHrvData(startDate: startDate, endDate: endDate)
case .heartRate:
return try await service.fetchHeartRateData(startDate: startDate, endDate: endDate)
case .walkingHeartRate:
return try await service.fetchWalkingHeartRateData(startDate: startDate, endDate: endDate)
case .restingHeartRate:
return try await service.fetchRestingHeartRateData(startDate: startDate, endDate: endDate)
case .sleepingHeartRate:
return try await service.fetchSleepingHeartRateData(startDate: startDate, endDate: endDate)
case .oxygenSaturation:
return try await service.fetchOxygenSaturationData(startDate: startDate, endDate: endDate)
case .activeEnergy:
return try await service.fetchActiveEnergyData(startDate: startDate, endDate: endDate)
case .exercise:
return try await service.fetchExerciseData(startDate: startDate, endDate: endDate)
case .stand:
return try await service.fetchStandData(startDate: startDate, endDate: endDate)
case .steps:
return try await service.fetchStepCountData(startDate: startDate, endDate: endDate)
case .sleepingWristTemperature:
return try await service.fetchSleepingWristTemperatureData(startDate: startDate, endDate: endDate)
case .respiratoryRate:
return try await service.fetchRespiratoryRateData(startDate: startDate, endDate: endDate)
case .irregularHeartRhythm:
return try await service.fetchIrregularHeartRhythmData(startDate: startDate, endDate: endDate)
case .unknown, .sleep:
return []
}
}
func uploadActivityTargetIfNeeded(
uploadTimeList: NativeHealthUploadTimeList,
service: HealthKitService
) async -> UploadTaskResult {
let startDate = uploadTimeList.latestDataTime(for: .activeEnergy)
?? Calendar.current.date(byAdding: .weekOfYear, value: -defaultUploadTimeWeek, to: Date())
?? Date(timeIntervalSinceNow: -7 * 24 * 60 * 60)
let endDate = Date()
debugLog(
"[activityTarget] upload started, range=\(Self.debugDateFormatter.string(from: startDate)) -> \(Self.debugDateFormatter.string(from: endDate))"
)
do {
guard let target = try await service.fetchActivityTargetData(startDate: startDate, endDate: endDate),
target.move != nil || target.stand != nil else {
debugLog("[activityTarget] no target data")
return UploadTaskResult(success: true, uploadedCount: 0, errorMessage: nil)
}
debugLog("[activityTarget] uploading, move=\(target.move.map(String.init) ?? "<nil>"), stand=\(target.stand.map(String.init) ?? "<nil>")")
try await uploadActivityTarget(target)
debugLog("[activityTarget] upload success")
return UploadTaskResult(success: true, uploadedCount: 1, errorMessage: nil)
} catch {
debugLog("[activityTarget] upload failed, error=\(error.localizedDescription)")
return UploadTaskResult(
success: false,
uploadedCount: 0,
errorMessage: "活动目标上传失败:\(error.localizedDescription)"
)
}
}
func processLastUploadTime() async throws -> NativeHealthUploadTimeList {
let localTimeList = uploadTimeRecorder.records
let serverTimeList = try? await fetchLastUploadTime()
var resultTimeList: [NativeHealthUploadTimeList.HealthUploadTime] = []
debugLog("processLastUploadTime started, hasServerTimeList=\(serverTimeList != nil)")
let fourWeeksAgo = Calendar.current.date(byAdding: .weekOfYear, value: -maxUploadTimeWeek, to: Date())
?? Date(timeIntervalSinceNow: -TimeInterval(maxUploadTimeWeek * 7 * 24 * 60 * 60))
let fourWeeksAgoMidnight = Calendar.current.startOfDay(for: fourWeeksAgo).timeIntervalSince1970
let oneWeekAgo = Calendar.current.date(byAdding: .weekOfYear, value: -defaultUploadTimeWeek, to: Date())
?? Date(timeIntervalSinceNow: -TimeInterval(defaultUploadTimeWeek * 7 * 24 * 60 * 60))
let oneWeekAgoMidnight = Calendar.current.startOfDay(for: oneWeekAgo).timeIntervalSince1970
let twoYearsAgo = Calendar.current.date(byAdding: .year, value: -firstUploadYear, to: Date())
?? Date(timeIntervalSinceNow: -TimeInterval(firstUploadYear * 365 * 24 * 60 * 60))
let twoYearsAgoMidnight = Calendar.current.startOfDay(for: twoYearsAgo).timeIntervalSince1970
for type in NativeHealthDataType.allCases where type != .unknown {
let localTime = localTimeList.latestTimeInterval(for: type)
let serverTime = serverTimeList?.latestTimeInterval(for: type)
let finalTime: TimeInterval
if let localTime, localTime > fourWeeksAgoMidnight {
finalTime = localTime
} else if let serverTime, serverTime > fourWeeksAgoMidnight {
finalTime = serverTime
} else if localTime != nil || serverTime != nil {
finalTime = oneWeekAgoMidnight
} else {
finalTime = twoYearsAgoMidnight
}
debugLog(
"[\(type.debugName)] resolved start time=\(Self.debugDateFormatter.string(from: Date(timeIntervalSince1970: finalTime))), local=\(localTime.map { Self.debugDateFormatter.string(from: Date(timeIntervalSince1970: $0)) } ?? "<nil>"), server=\(serverTime.map { Self.debugDateFormatter.string(from: Date(timeIntervalSince1970: $0)) } ?? "<nil>")"
)
resultTimeList.append(
NativeHealthUploadTimeList.HealthUploadTime(
dataType: type,
latestDataTime: finalTime
)
)
}
return NativeHealthUploadTimeList(latestDataTimeList: resultTimeList)
}
func uploadCommon(_ data: [NativeHealthDataPoint]) async throws {
let list = data.map {
[
"data_type": $0.dataType.rawValue,
"time": $0.time,
"value": $0.value,
] as [String: Any]
}
try await request(path: "/client/doublefeel/health/data_upload/common/", method: "POST", body: ["data_list": list])
}
func uploadSleep(_ data: [NativeSleepInterval]) async throws {
let list = data.map {
[
"data_type": $0.dataType,
"from_time": $0.fromTime,
"to_time": $0.toTime,
] as [String: Any]
}
try await request(path: "/client/doublefeel/health/data_upload/sleep/", method: "POST", body: ["data_list": list])
}
func uploadActivityTarget(_ target: NativeActivityTarget) async throws {
var body: [String: Any] = [:]
body["move"] = target.move
body["stand"] = target.stand
try await request(path: "/client/doublefeel/health/activity_target/", method: "POST", body: body)
}
func fetchLastUploadTime() async throws -> NativeHealthUploadTimeList {
let data = try await request(path: "/client/doublefeel/health/data_upload/common/", method: "GET")
return try NativeHealthUploadTimeList.decode(from: data)
}
@discardableResult
func request(path: String, method: String, body: [String: Any]? = nil) async throws -> Data {
guard let baseURL = URL(string: AppShared.shared.baseUrl),
let url = URL(string: path, relativeTo: baseURL)?.absoluteURL else {
throw NativeHealthUploadError.invalidServerURL
}
guard let accessToken = AppShared.shared.token, !accessToken.isEmpty else {
throw NativeHealthUploadError.missingAccessToken
}
var request = URLRequest(url: url)
request.httpMethod = method
request.timeoutInterval = 60
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue(accessToken, forHTTPHeaderField: "access_token")
request.setValue(AppShared.shared.agent.finalUA, forHTTPHeaderField: "User-Agent")
if let body {
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONSerialization.data(withJSONObject: body)
}
let (data, response) = try await session.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw NativeHealthUploadError.invalidResponse
}
guard (200..<300).contains(httpResponse.statusCode) else {
throw NativeHealthUploadError.requestFailed(
path: path,
statusCode: httpResponse.statusCode,
body: String(data: data, encoding: .utf8)
)
}
return data
}
static let debugDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return formatter
}()
func debugLog(_ message: String) {
#if DEBUG || CI_ENV
print("[NativeHealthDataUploader] \(message)")
#endif
}
}
struct NativeHealthUploadTimeList: Codable {
struct HealthUploadTime: Codable {
let dataType: NativeHealthDataType?
let latestDataTime: TimeInterval?
enum CodingKeys: String, CodingKey {
case dataType = "data_type"
case latestDataTime = "latest_data_time"
}
}
var latestDataTimeList: [HealthUploadTime]
enum CodingKeys: String, CodingKey {
case latestDataTimeList = "latest_data_time_list"
}
func latestDataTime(for type: NativeHealthDataType) -> Date? {
latestTimeInterval(for: type).map(Date.init(timeIntervalSince1970:))
}
func latestTimeInterval(for type: NativeHealthDataType) -> TimeInterval? {
latestDataTimeList.first { $0.dataType == type }?.latestDataTime
}
static func decode(from data: Data) throws -> NativeHealthUploadTimeList {
let decoder = JSONDecoder()
if let direct = try? decoder.decode(NativeHealthUploadTimeList.self, from: data) {
return direct
}
let wrapped = try decoder.decode(HealthUploadTimeListResponse.self, from: data)
if let data = wrapped.data {
return data
}
throw NativeHealthUploadError.invalidResponse
}
}
private struct HealthUploadTimeListResponse: Decodable {
let data: NativeHealthUploadTimeList?
}
struct NativeHealthUploadTimeRecorder {
private var cachedRecords: NativeHealthUploadTimeList?
private static let cacheKey = "HealthUploadlocalRecord_records"
var records: NativeHealthUploadTimeList {
mutating get {
if let cachedRecords {
return cachedRecords
}
let records = Self.loadFromCache() ?? NativeHealthUploadTimeList(latestDataTimeList: [])
cachedRecords = records
return records
}
set {
cachedRecords = newValue
Self.saveToCache(newValue)
}
}
init(records: NativeHealthUploadTimeList? = nil) {
cachedRecords = records
}
mutating func save(date: Date, for type: NativeHealthDataType) {
var records = records
records.latestDataTimeList.removeAll { $0.dataType == type }
records.latestDataTimeList.append(
NativeHealthUploadTimeList.HealthUploadTime(
dataType: type,
latestDataTime: date.timeIntervalSince1970
)
)
self.records = records
}
static func clearCache() {
UserDefaults.standard.removeObject(forKey: cacheKeyForCurrentUser())
}
private static func loadFromCache() -> NativeHealthUploadTimeList? {
guard let data = UserDefaults.standard.data(forKey: cacheKeyForCurrentUser()) else {
return nil
}
return try? JSONDecoder().decode(NativeHealthUploadTimeList.self, from: data)
}
private static func saveToCache(_ records: NativeHealthUploadTimeList) {
guard let data = try? JSONEncoder().encode(records) else {
return
}
UserDefaults.standard.set(data, forKey: cacheKeyForCurrentUser())
}
private static func cacheKeyForCurrentUser() -> String {
let userId = AppShared.shared.userId
?? AppShared.shared.userSummary?.meUserInfo?.id.map(String.init)
?? AppGroupConstants.defaults?.string(forKey: AppGroupConstants.Key.userId)
?? ""
return cacheKey + userId
}
}
private extension NativeHealthDataType {
var debugName: String {
switch self {
case .unknown:
return "unknown"
case .hrv:
return "hrv"
case .heartRate:
return "heartRate"
case .oxygenSaturation:
return "oxygenSaturation"
case .activeEnergy:
return "activeEnergy"
case .exercise:
return "exercise"
case .stand:
return "stand"
case .steps:
return "steps"
case .walkingHeartRate:
return "walkingHeartRate"
case .restingHeartRate:
return "restingHeartRate"
case .sleepingHeartRate:
return "sleepingHeartRate"
case .sleepingWristTemperature:
return "sleepingWristTemperature"
case .respiratoryRate:
return "respiratoryRate"
case .irregularHeartRhythm:
return "irregularHeartRhythm"
case .sleep:
return "sleep"
}
}
}
... ...
//
// NSArray+OBSMTLManipulationAdditions.h
// Mantle
//
// Created by Josh Abernathy on 9/19/12.
// Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSArray (OBSMTLManipulationAdditions)
/// The first object in the array or nil if the array is empty.
/// Forwards to `firstObject` which has been first declared in iOS7, but works with iOS4/10.6.
@property (nonatomic, readonly, strong) id obs_mtl_firstObject;
/// Returns a new array without all instances of the given object.
- (NSArray *)obs_mtl_arrayByRemovingObject:(id)object;
/// Returns a new array without the first object. If the array is empty, it
/// returns the empty array.
- (NSArray *)obs_mtl_arrayByRemovingFirstObject;
/// Returns a new array without the last object. If the array is empty, it
/// returns the empty array.
- (NSArray *)obs_mtl_arrayByRemovingLastObject;
@end
... ...
//
// NSDictionary+OBSMTLJSONKeyPath.h
// Mantle
//
// Created by Robert Böhnke on 19/03/14.
// Copyright (c) 2014 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDictionary (OBSMTLJSONKeyPath)
/// Looks up the value of a key path in the receiver.
///
/// JSONKeyPath - The key path that should be resolved. Every element along this
/// key path needs to be an instance of NSDictionary for the
/// resolving to be successful.
/// success - If not NULL, this will be set to a boolean indicating whether
/// the key path was resolved successfully.
/// error - If not NULL, this may be set to an error that occurs during
/// resolving the value.
///
/// Returns the value for the key path which may be nil. Clients should inspect
/// the success parameter to decide how to proceed with the result.
- (id)obs_mtl_valueForJSONKeyPath:(NSString *)JSONKeyPath success:(BOOL *)success error:(NSError **)error;
@end
... ...
//
// NSDictionary+OBSMTLManipulationAdditions.h
// Mantle
//
// Created by Justin Spahr-Summers on 2012-09-24.
// Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDictionary (OBSMTLManipulationAdditions)
/// Merges the keys and values from the given dictionary into the receiver. If
/// both the receiver and `dictionary` have a given key, the value from
/// `dictionary` is used.
///
/// Returns a new dictionary containing the entries of the receiver combined with
/// those of `dictionary`.
- (NSDictionary *)obs_mtl_dictionaryByAddingEntriesFromDictionary:(NSDictionary *)dictionary;
/// Creates a new dictionary with all the entries for the given keys removed from
/// the receiver.
- (NSDictionary *)obs_mtl_dictionaryByRemovingValuesForKeys:(NSArray *)keys;
@end
@interface NSDictionary (OBSMTLManipulationAdditions_Deprecated)
- (NSDictionary *)obs_mtl_dictionaryByRemovingEntriesWithKeys:(NSSet *)keys __attribute__((deprecated("Replaced by -obs_mtl_dictionaryByRemovingValuesForKeys:")));
@end
... ...
//
// NSDictionary+OBSMTLMappingAdditions.h
// Mantle
//
// Created by Robert Böhnke on 10/31/13.
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDictionary (OBSMTLMappingAdditions)
/// Creates an identity mapping for serialization.
///
/// class - A subclass of OBSMTLModel.
///
/// Returns a dictionary that maps all properties of the given class to
/// themselves.
+ (NSDictionary *)obs_mtl_identityPropertyMapWithModel:(Class)modelClass;
@end
... ...
//
// NSError+OBSMTLModelException.h
// Mantle
//
// Created by Robert Böhnke on 7/6/13.
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSError (OBSMTLModelException)
/// Creates a new error for an exception that occurred during updating an
/// OBSMTLModel.
///
/// exception - The exception that was thrown while updating the model.
/// This argument must not be nil.
///
/// Returns an error that takes its localized description and failure reason
/// from the exception.
+ (instancetype)obs_mtl_modelErrorWithException:(NSException *)exception;
@end
... ...
//
// NSObject+OBSMTLComparisonAdditions.h
// Mantle
//
// Created by Josh Vera on 10/26/12.
// Copyright (c) 2012 GitHub. All rights reserved.
//
// Portions copyright (c) 2011 Bitswift. All rights reserved.
// See the LICENSE file for more information.
//
#import <Foundation/Foundation.h>
/// Returns whether both objects are identical or equal via -isEqual:
BOOL OBSMTLEqualObjects(id obj1, id obj2);
... ...
//
// NSValueTransformer+OBSMTLInversionAdditions.h
// Mantle
//
// Created by Justin Spahr-Summers on 2013-05-18.
// Copyright (c) 2013 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSValueTransformer (OBSMTLInversionAdditions)
/// Flips the direction of the receiver's transformation, such that
/// -transformedValue: will become -reverseTransformedValue:, and vice-versa.
///
/// The receiver must allow reverse transformation.
///
/// Returns an inverted transformer.
- (NSValueTransformer *)obs_mtl_invertedTransformer;
@end
... ...
//
// NSValueTransformer+OBSMTLPredefinedTransformerAdditions.h
// Mantle
//
// Created by Justin Spahr-Summers on 2012-09-27.
// Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OBSMTLTransformerErrorHandling.h"
/// The name for a value transformer that converts strings into URLs and back.
extern NSString *const OBSMTLURLValueTransformerName;
/// The name for a value transformer that converts strings into NSUUIDs and back.
extern NSString *const OBSMTLUUIDValueTransformerName;
/// Ensure an NSNumber is backed by __NSCFBoolean/CFBooleanRef
///
/// NSJSONSerialization, and likely other serialization libraries, ordinarily
/// serialize NSNumbers as numbers, and thus booleans would be serialized as
/// 0/1. The exception is when the NSNumber is backed by __NSCFBoolean, which,
/// though very much an implementation detail, is detected and serialized as a
/// proper boolean.
extern NSString *const OBSMTLBooleanValueTransformerName;
@interface NSValueTransformer (OBSMTLPredefinedTransformerAdditions)
/// An optionally reversible transformer which applies the given transformer to
/// each element of an array.
///
/// transformer - The transformer to apply to each element. If the transformer
/// is reversible, the transformer returned by this method will be
/// reversible. This argument must not be nil.
///
/// Returns a transformer which applies a transformation to each element of an
/// array.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_arrayMappingTransformerWithTransformer:(NSValueTransformer *)transformer;
/// A reversible value transformer to transform between the keys and objects of a
/// dictionary.
///
/// dictionary - The dictionary whose keys and values should be
/// transformed between. This argument must not be nil.
/// defaultValue - The result to fall back to, in case no key matching the
/// input value was found during a forward transformation.
/// reverseDefaultValue - The result to fall back to, in case no value matching
/// the input value was found during a reverse
/// transformation.
///
/// Can for example be used for transforming between enum values and their string
/// representation.
///
/// NSValueTransformer *valueTransformer = [NSValueTransformer obs_mtl_valueMappingTransformerWithDictionary:@{
/// @"foo": @(EnumDataTypeFoo),
/// @"bar": @(EnumDataTypeBar),
/// } defaultValue: @(EnumDataTypeUndefined) reverseDefaultValue: @"undefined"];
///
/// Returns a transformer which will map from keys to objects for forward
/// transformations, and from objects to keys for reverse transformations.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_valueMappingTransformerWithDictionary:(NSDictionary *)dictionary defaultValue:(id)defaultValue reverseDefaultValue:(id)reverseDefaultValue;
/// Returns a value transformer created by calling
/// `+obs_mtl_valueMappingTransformerWithDictionary:defaultValue:reverseDefaultValue:`
/// with a default value of `nil` and a reverse default value of `nil`.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_valueMappingTransformerWithDictionary:(NSDictionary *)dictionary;
/// A reversible value transformer to transform between a date and its string
/// representation
///
/// dateFormat - The date format used by the date formatter (http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Field_Symbol_Table)
/// calendar - The calendar used by the date formatter
/// locale - The locale used by the date formatter
/// timeZone - The time zone used by the date formatter
///
/// Returns a transformer which will map from strings to dates for forward
/// transformations, and from dates to strings for reverse transformations.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_dateTransformerWithDateFormat:(NSString *)dateFormat calendar:(NSCalendar *)calendar locale:(NSLocale *)locale timeZone:(NSTimeZone *)timeZone defaultDate:(NSDate *)defaultDate;
/// Returns a value transformer created by calling
/// `+obs_mtl_dateTransformerWithDateFormat:calendar:locale:timeZone:defaultDate:`
/// with a calendar, locale, time zone and default date of `nil`.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_dateTransformerWithDateFormat:(NSString *)dateFormat locale:(NSLocale *)locale;
/// A reversible value transformer to transform between a number and its string
/// representation
///
/// numberStyle - The number style used by the number formatter
///
/// Returns a transformer which will map from strings to numbers for forward
/// transformations, and from numbers to strings for reverse transformations.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_numberTransformerWithNumberStyle:(NSNumberFormatterStyle)numberStyle locale:(NSLocale *)locale;
/// A reversible value transformer to transform between an object and its string
/// representation
///
/// formatter - The formatter used to perform the transformation
/// objectClass - The class of object that the formatter operates on
///
/// Returns a transformer which will map from strings to objects for forward
/// transformations, and from objects to strings for reverse transformations.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_transformerWithFormatter:(NSFormatter *)formatter forObjectClass:(Class)objectClass;
/// A value transformer that errors if the transformed value are not of the given
/// class.
///
/// class - The expected class. This argument must not be nil.
///
/// Returns a transformer which will return an error if the transformed in value
/// is not a member of class. Otherwise, the value is simply passed through.
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_validatingTransformerForClass:(Class)modelClass;
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_JSONDictionaryTransformerWithModelClass:(Class)modelClass __attribute__((deprecated("Replaced by +[OBSMTLJSONAdapter dictionaryTransformerWithModelClass:]")));
+ (NSValueTransformer<OBSMTLTransformerErrorHandling> *)obs_mtl_JSONArrayTransformerWithModelClass:(Class)modelClass __attribute__((deprecated("Replaced by +[OBSMTLJSONAdapter arrayTransformerWithModelClass:]")));
@end
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBS_h
#define OBS_h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//! Project version number for OBS.
FOUNDATION_EXPORT double OBSVersionNumber;
//! Project version string for OBS.
FOUNDATION_EXPORT unsigned char OBSVersionString[];
NS_ASSUME_NONNULL_END
#import "OBSBaseNetworking.h"
#import "OBSClient.h"
#import "OBSServiceBaseModel.h"
#import "OBSUtils.h"
#import "OBSBolts.h"
#import "OBSServiceCredentialProvider.h"
#import "OBSMantle.h"
#import "OBSLogging.h"
#import "OBSServiceCommonEntities.h"
#pragma mark service models
#pragma mark presign
#import "OBSPreSignedURLModel.h"
#pragma mark bucket
#import "OBSListBucketsModel.h"
#import "OBSCreateBucketModel.h"
#import "OBSGetBucketMetaDataModel.h"
#import "OBSGetBucketLocationModel.h"
#import "OBSGetBucketStorageInfoModel.h"
#import "OBSSetBucketQuotaModel.h"
#import "OBSGetBucketQuotaModel.h"
#import "OBSSetBucketACLModel.h"
#import "OBSGetBucketACLModel.h"
#import "OBSSetBucketCORSModel.h"
#import "OBSGetBucketCORSModel.h"
#import "OBSDeleteBucketCORSModel.h"
#import "OBSSetBucketStoragePolicyModel.h"
#import "OBSGetBucketStoragePolicyModel.h"
#import "OBSSetBucketLoggingModel.h"
#import "OBSGetBucketLoggingModel.h"
#import "OBSSetBucketPolicyModel.h"
#import "OBSGetBucketPolicyModel.h"
#import "OBSDeleteBucketPolicyModel.h"
#import "OBSSetBucketLifecycleModel.h"
#import "OBSGetBucketLifecycleModel.h"
#import "OBSDeleteBucketLifecycleModel.h"
#import "OBSSetBucketWebsiteModel.h"
#import "OBSGetBucketWebsiteModel.h"
#import "OBSDeleteBucketWebsiteModel.h"
#import "OBSSetBucketVersioningModel.h"
#import "OBSGetBucketVersioningModel.h"
#import "OBSSetBucketNotificationModel.h"
#import "OBSGetBucketNotificationModel.h"
#import "OBSOptionsBucketModel.h"
#import "OBSListMultipartUploadsModel.h"
#import "OBSSetBucketTaggingModel.h"
#import "OBSGetBucketTaggingModel.h"
#import "OBSDeleteBucketTaggingModel.h"
#import "OBSDeleteBucketModel.h"
#import "OBSReplicateBucketModel.h"
#import "OBSGetReplicateBucketModel.h"
#import "OBSDeleteReplicateBucketModel.h"
#import "OBSAppendObjectModel.h"
#pragma mark object
#import "OBSPutObjectModel.h"
#import "OBSGetObjectModel.h"
#import "OBSCopyObjectModel.h"
#import "OBSSetObjectACLModel.h"
#import "OBSGetObjectACLModel.h"
#import "OBSListObjectsModel.h"
#import "OBSListObjectsVersionsModel.h"
#import "OBSGetObjectMetaDataModel.h"
#import "OBSOptionsObjectModel.h"
#import "OBSRestoreObjectModel.h"
#import "OBSInitiateMultipartUploadModel.h"
#import "OBSUploadPartModel.h"
#import "OBSCopyPartModel.h"
#import "OBSListPartsModel.h"
#import "OBSCompleteMultipartUploadModel.h"
#import "OBSAbortMultipartUploadModel.h"
#import "OBSDeleteObjectModel.h"
#import "OBSDeleteObjectsModel.h"
#pragma mark additional
#import "OBSDownloadFileModel.h"
#import "OBSUploadFileModel.h"
#import "OBSUploadFileModel.h"
#import "OBSGetBucketLocationModel.h"
#import "OBSGetBucketStorageInfoModel.h"
#import "OBSSetBucketQuotaModel.h"
#import "OBSGetBucketStorageInfoModel.h"
#import "OBSServiceUtils.h"
#import "OBSListPartsModel.h"
#import "OBSAbortMultipartUploadModel.h"
#import "OBSCompleteMultipartUploadModel.h"
#import "OBSDownloadFileModel.h"
#import "OBSDeleteObjectModel.h"
#import "OBSDeleteObjectsModel.h"
#endif /* OBS_h */
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSAbortMultipartUploadModel_h
#define OBSAbortMultipartUploadModel_h
#import "OBSBaseNetworking.h"
#import "OBSClient.h"
#import "OBSServiceBaseModel.h"
#import "OBSServiceConstDefinition.h"
@class OBSAbstractEncryption;
//request
#pragma mark - request
/**
取消多段上传任务
*/
@protocol OBSAbortMultipartUploadProtocol<NSObject>
@required
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
/**
对象名
*/
@property (nonatomic, strong, nonnull) NSString *objectKey;
/**
多段上传任务ID
*/
@property (nonatomic, strong, nonnull) NSString *uploadID;
@end
/**
取消多段上传任务request
*/
@interface OBSAbortMultipartUploadRequest : OBSBaseRequest<OBSAbortMultipartUploadProtocol>
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
/**
对象key
*/
@property (nonatomic, strong, nonnull) NSString *objectKey;
/**
多段上传任务ID
*/
@property (nonatomic, strong, nonnull) NSString *uploadID;
/**
初始化取消多段上传任务request
@param bucketName 桶名
@param objectKey 对象KEY
@param uploadID 多段上传任务ID
@return 取消多段上传request
*/
-(instancetype)initWithBucketName:(NSString*) bucketName objectKey: (NSString*) objectKey uploadID:(NSString*) uploadID;
@end
#pragma mark - networking request
@interface OBSNetworkingAbortMultipartUploadRequest : OBSServiceNetworkingCommandRequest
@end
//response
#pragma mark - response
/**
取消多段上传response
*/
@interface OBSAbortMultipartUploadResponse: OBSServiceResponse
@end
//client method
#pragma mark - client method
@interface OBSClient(abortMultipartUpload)
/**
取消多段上传
@param request 取消多段上传request
@param completionHandler 取消多段上传回调
@return OBSBFTask
*/
- (OBSBFTask*)abortMultipartUpload:(__kindof OBSBaseRequest<OBSAbortMultipartUploadProtocol>*)request
completionHandler:(void (^)(OBSAbortMultipartUploadResponse * response, NSError * error))completionHandler;
@end
#endif /* OBSAbortMultipartUploadModel_h */
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSAppendObjectRequest_h
#define OBSAppendObjectRequest_h
#import "OBSBaseNetworking.h"
#import "OBSClient.h"
#import "OBSServiceBaseModel.h"
#import "OBSServiceConstDefinition.h"
//request
@class OBSAbstractEncryption;
#pragma mark - request
/**
上传对象
*/
@protocol OBSAppendObjectProtocol<NSObject>
@required
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
/**
对象名
*/
@property (nonatomic, strong, nonnull) NSString *objectKey;
/**
MD5值
*/
@property (nonatomic, strong, nonnull) NSString *contentMD5;
/**
对象访问策略
*/
@property (nonatomic, assign) OBSACLPolicy objectACLPolicy;
/**
对象存储类型
*/
@property (nonatomic, assign) OBSStorageClass storageClass;
/**
元数据字典
*/
@property (nonatomic, strong, nullable) NSDictionary *metaDataDict;
/**
重定向地址
*/
@property (nonatomic, strong, nonnull) NSString *websiteRedirectLocation;
/**
加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *encryption;
/**
上传进度
*/
@property (nonatomic, copy, nonnull) OBSNetworkingUploadProgressBlock uploadProgressBlock;
@end
/**
上传对象request父类
*/
@interface OBSAbstractAppendObjectRequest : OBSBaseRequest<OBSAppendObjectProtocol>
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
/**
对象描述标识
*/
@property (nonatomic, strong, nonnull) NSString *objectKey;
/**
对象的MD5
*/
@property (nonatomic, strong, nonnull) NSString *contentMD5;
/**
对象的ACL
*/
@property (nonatomic, assign) OBSACLPolicy objectACLPolicy;
/**
对象存储类型
*/
@property (nonatomic, assign) OBSStorageClass storageClass;
/**
对象元数据字典
*/
@property (nonatomic, strong, nullable) NSDictionary *metaDataDict;
/**
对象重定向地址
*/
@property (nonatomic, strong, nonnull) NSString *websiteRedirectLocation;
/**
创建对象时,使用此头域授权domain下所有用户有读对象和获取对象元数据的权限
*/
@property (nonatomic, strong, nonnull) NSString *granteRead;
/**
创建对象时,使用此头域授权domain下所有用户有读对象和获取对象元数据的权限
*/
@property (nonatomic, strong, nonnull) NSString *granteReadAcp;
/**
创建对象时,使用此头域授权domain下所有用户有获取对象ACL的权限
*/
@property (nonatomic, strong, nonnull) NSString *granteWriteAcp;
/**
创建对象时,使用此头域授权domain下所有用户有读对象、获取对象元数据、获取对象ACL、写对象ACL的权限
*/
@property (nonatomic, strong, nonnull) NSString *granteFullControl;
/**
此参数的值是一个URL,用于指定当此次请求操作成功响应后的重定向的地址
如果此参数值有效且操作成功,响应码为303,location头域由此参数以及桶名、对象名、对象的ETag组成
如果此参数值无效,忽略此参数的作用,响应码为204,location头域为对象地址
*/
@property (nonatomic, strong, nonnull) NSString *actionRedirect;
/**
表示上传对象的过期时间,单位是天
*/
@property (nonatomic, strong, nonnull) NSNumber *expires;
/**
追加写位置
*/
@property (nonatomic, strong, nonnull) NSNumber *position;
/**
加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *encryption;
/**
上传对象时的回调
*/
@property (nonatomic, copy, nonnull) OBSNetworkingUploadProgressBlock uploadProgressBlock;
/**
自定义MIME类型
*/
@property (nonatomic, strong, nonnull) NSString *customContentType;
@end
/**
流式上传对象request
*/
@interface OBSAppendObjectWithDataRequest: OBSAbstractAppendObjectRequest
/**
上传的数据
*/
@property (nonatomic, strong, nonnull) NSData *uploadData;
/**
初始化流式上传对象request
@param bucketName 桶名
@param objectKey 对象名
@param data 需要上传的对象数据
@return 流式上传对象request
*/
-(instancetype)initWithBucketName:(NSString*) bucketName objectKey: (NSString*) objectKey uploadData:(NSData*) data;
/**
初始上传网络流对象request
@param bucketName 桶名
@param objectKey 对象名
@param dataURL 需要上传的网络流地址
@return 上传网络流对象request
*/
-(instancetype)initWithBucketName:(NSString*) bucketName objectKey: (NSString*) objectKey uploadDataURL:(NSURL*) dataURL;
@end
/**
通过文件上传对象request
*/
@interface OBSAppendObjectWithFileRequest: OBSAbstractAppendObjectRequest
/**
文件路径
*/
@property (nonatomic, strong, nonnull) NSString *uploadFilePath;
@property (nonatomic, assign) BOOL background;
/**
初始化通过文件上传对象request
@param bucketName 桶名
@param objectKey 对象描述标识
@param uploadFilePath 文件路径
@return 通过文件上传对象request
*/
-(instancetype)initWithBucketName:(NSString*) bucketName objectKey: (NSString*) objectKey uploadFilePath:(NSString*) uploadFilePath;
@end
#pragma mark - networking request
@interface OBSNetworkingAppendObjectWithDataRequest : OBSServiceNetworkingUploadDataRequest
@end
@interface OBSNetworkingAppendObjectWithFileRequest : OBSServiceNetworkingUploadFileRequest
@end
//response
#pragma mark - response
/**
上传对象响应
*/
@interface OBSAppendObjectResponse: OBSServiceResponse
/**
对象etag值
*/
@property (nonatomic, strong, nonnull) NSString *etag;
/**
如果桶开启了多版本状态 则返回版本号
*/
@property (nonatomic, strong, nonnull) NSString *versionID;
/**
对象存储类型
*/
@property (nonatomic, assign) OBSStorageClass storageClass;
/**
对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *encryption;
@end
//client method
#pragma mark - client method
@interface OBSClient(appendObject)
/**
上传对象
@param request 上传对象request
@param completionHandler 上传对象回调
@return OBSBFTask
*/
- (OBSBFTask*)appendObject:(__kindof OBSBaseRequest<OBSAppendObjectProtocol>*)request
completionHandler:(void (^)(OBSAppendObjectResponse * response, NSError * error))completionHandler;
@end
#endif /* OBSAppendObjectRequest_h */
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
#import "OBSBFCancellationTokenRegistration.h"
NS_ASSUME_NONNULL_BEGIN
/*!
A block that will be called when a token is cancelled.
*/
typedef void(^OBSBFCancellationBlock)(void);
/*!
The consumer view of a CancellationToken.
Propagates notification that operations should be canceled.
A OBSBFCancellationToken has methods to inspect whether the token has been cancelled.
*/
@interface OBSBFCancellationToken : NSObject
/*!
Whether cancellation has been requested for this token source.
*/
@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
/*!
Register a block to be notified when the token is cancelled.
If the token is already cancelled the delegate will be notified immediately.
*/
- (OBSBFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(OBSBFCancellationBlock)block;
@end
NS_ASSUME_NONNULL_END
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
Represents the registration of a cancellation observer with a cancellation token.
Can be used to unregister the observer at a later time.
*/
@interface OBSBFCancellationTokenRegistration : NSObject
/*!
Removes the cancellation observer registered with the token
and releases all resources associated with this registration.
*/
- (void)dispose;
@end
NS_ASSUME_NONNULL_END
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class OBSBFCancellationToken;
/*!
OBSBFCancellationTokenSource represents the producer side of a CancellationToken.
Signals to a CancellationToken that it should be canceled.
It is a cancellation token that also has methods
for changing the state of a token by cancelling it.
*/
@interface OBSBFCancellationTokenSource : NSObject
/*!
Creates a new cancellation token source.
*/
+ (instancetype)cancellationTokenSource;
/*!
The cancellation token associated with this CancellationTokenSource.
*/
@property (nonatomic, strong, readonly) OBSBFCancellationToken *token;
/*!
Whether cancellation has been requested for this token source.
*/
@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
/*!
Cancels the token if it has not already been cancelled.
*/
- (void)cancel;
/*!
Schedules a cancel operation on this CancellationTokenSource after the specified number of milliseconds.
@param millis The number of milliseconds to wait before completing the returned task.
If delay is `0` the cancel is executed immediately. If delay is `-1` any scheduled cancellation is stopped.
*/
- (void)cancelAfterDelay:(int)millis;
/*!
Releases all resources associated with this token source,
including disposing of all registrations.
*/
- (void)dispose;
@end
NS_ASSUME_NONNULL_END
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
An object that can run a given block.
*/
@interface OBSBFExecutor : NSObject
/*!
Returns a default executor, which runs continuations immediately until the call stack gets too
deep, then dispatches to a new GCD queue.
*/
+ (instancetype)defaultExecutor;
/*!
Returns an executor that runs continuations on the thread where the previous task was completed.
*/
+ (instancetype)immediateExecutor;
/*!
Returns an executor that runs continuations on the main thread.
*/
+ (instancetype)mainThreadExecutor;
/*!
Returns a new executor that uses the given block to execute continuations.
@param block The block to use.
*/
+ (instancetype)executorWithBlock:(void(^)(void(^block)(void)))block;
/*!
Returns a new executor that runs continuations on the given queue.
@param queue The instance of `dispatch_queue_t` to dispatch all continuations onto.
*/
+ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue;
/*!
Returns a new executor that runs continuations on the given queue.
@param queue The instance of `NSOperationQueue` to run all continuations on.
*/
+ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue;
/*!
Runs the given block using this executor's particular strategy.
@param block The block to execute.
*/
- (void)execute:(void(^)(void))block;
@end
NS_ASSUME_NONNULL_END
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
#pragma once
/**
This exists to use along with `OBSBFTask` and `OBSBFTaskCompletionSource`.
Instead of returning a `OBSBFTask` with no generic type, or a generic type of 'NSNull'
when there is no usable result from a task, we use the type 'OBSBFVoid', which will always have a value of `nil`.
This allows you to provide a more enforced API contract to the caller,
as sending any message to `OBSBFVoid` will result in a compile time error.
*/
@class _OBSBFVoid_Nonexistant;
typedef _OBSBFVoid_Nonexistant *OBSBFVoid;
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
#import "OBSBFCancellationToken.h"
#import "OBSBFGeneric.h"
NS_ASSUME_NONNULL_BEGIN
/*!
Error domain used if there was multiple errors on <OBSBFTask taskForCompletionOfAllTasks:>.
*/
extern NSString *const OBSBFTaskErrorDomain;
/*!
An error code used for <OBSBFTask taskForCompletionOfAllTasks:>, if there were multiple errors.
*/
extern NSInteger const kOBSBFMultipleErrorsError;
/*!
An error userInfo key used if there were multiple errors on <OBSBFTask taskForCompletionOfAllTasks:>.
Value type is `NSArray<NSError *> *`.
*/
extern NSString *const OBSBFTaskMultipleErrorsUserInfoKey;
@class OBSBFExecutor;
@class OBSBFTask;
/*!
The consumer view of a Task. A OBSBFTask has methods to
inspect the state of the task, and to add continuations to
be run once the task is complete.
*/
@interface OBSBFTask<__covariant ResultType> : NSObject
/*!
A block that can act as a continuation for a task.
*/
typedef __nullable id(^OBSBFContinuationBlock)(OBSBFTask<ResultType> *t);
/*!
Creates a task that is already completed with the given result.
@param result The result for the task.
*/
+ (instancetype)taskWithResult:(nullable ResultType)result;
/*!
Creates a task that is already completed with the given error.
@param error The error for the task.
*/
+ (instancetype)taskWithError:(NSError *)error;
/*!
Creates a task that is already cancelled.
*/
+ (instancetype)cancelledTask;
/*!
Returns a task that will be completed (with result == nil) once
all of the input tasks have completed.
@param tasks An `NSArray` of the tasks to use as an input.
*/
+ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray<OBSBFTask *> *)tasks;
/*!
Returns a task that will be completed once all of the input tasks have completed.
If all tasks complete successfully without being faulted or cancelled the result will be
an `NSArray` of all task results in the order they were provided.
@param tasks An `NSArray` of the tasks to use as an input.
*/
+ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray<OBSBFTask *> *)tasks;
/*!
Returns a task that will be completed once there is at least one successful task.
The first task to successuly complete will set the result, all other tasks results are
ignored.
@param tasks An `NSArray` of the tasks to use as an input.
*/
+ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray<OBSBFTask *> *)tasks;
/*!
Returns a task that will be completed a certain amount of time in the future.
@param millis The approximate number of milliseconds to wait before the
task will be finished (with result == nil).
*/
+ (OBSBFTask<OBSBFVoid> *)taskWithDelay:(int)millis;
/*!
Returns a task that will be completed a certain amount of time in the future.
@param millis The approximate number of milliseconds to wait before the
task will be finished (with result == nil).
@param token The cancellation token (optional).
*/
+ (OBSBFTask<OBSBFVoid> *)taskWithDelay:(int)millis cancellationToken:(nullable OBSBFCancellationToken *)token;
/*!
Returns a task that will be completed after the given block completes with
the specified executor.
@param executor A OBSBFExecutor responsible for determining how the
continuation block will be run.
@param block The block to immediately schedule to run with the given executor.
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
+ (instancetype)taskFromExecutor:(OBSBFExecutor *)executor withBlock:(nullable id (^)(void))block;
// Properties that will be set on the task once it is completed.
/*!
The result of a successful task.
*/
@property (nullable, nonatomic, strong, readonly) ResultType result;
/*!
The error of a failed task.
*/
@property (nullable, nonatomic, strong, readonly) NSError *error;
/*!
Whether this task has been cancelled.
*/
@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled;
/*!
Whether this task has completed due to an error.
*/
@property (nonatomic, assign, readonly, getter=isFaulted) BOOL faulted;
/*!
Whether this task has completed.
*/
@property (nonatomic, assign, readonly, getter=isCompleted) BOOL completed;
/*!
Enqueues the given block to be run once this task is complete.
This method uses a default execution strategy. The block will be
run on the thread where the previous task completes, unless the
the stack depth is too deep, in which case it will be run on a
dispatch queue with default priority.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithBlock:(OBSBFContinuationBlock)block NS_SWIFT_NAME(continueWith(block:));
/*!
Enqueues the given block to be run once this task is complete.
This method uses a default execution strategy. The block will be
run on the thread where the previous task completes, unless the
the stack depth is too deep, in which case it will be run on a
dispatch queue with default priority.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithBlock:(OBSBFContinuationBlock)block
cancellationToken:(nullable OBSBFCancellationToken *)cancellationToken NS_SWIFT_NAME(continueWith(block:cancellationToken:));
/*!
Enqueues the given block to be run once this task is complete.
@param executor A OBSBFExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithExecutor:(OBSBFExecutor *)executor
withBlock:(OBSBFContinuationBlock)block NS_SWIFT_NAME(continueWith(executor:block:));
/*!
Enqueues the given block to be run once this task is complete.
@param executor A OBSBFExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
his method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithExecutor:(OBSBFExecutor *)executor
block:(OBSBFContinuationBlock)block
cancellationToken:(nullable OBSBFCancellationToken *)cancellationToken
NS_SWIFT_NAME(continueWith(executor:block:cancellationToken:));
/*!
Identical to continueWithBlock:, except that the block is only run
if this task did not produce a cancellation or an error.
If it did, then the failure will be propagated to the returned
task.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithSuccessBlock:(OBSBFContinuationBlock)block NS_SWIFT_NAME(continueOnSuccessWith(block:));
/*!
Identical to continueWithBlock:, except that the block is only run
if this task did not produce a cancellation or an error.
If it did, then the failure will be propagated to the returned
task.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithSuccessBlock:(OBSBFContinuationBlock)block
cancellationToken:(nullable OBSBFCancellationToken *)cancellationToken
NS_SWIFT_NAME(continueOnSuccessWith(block:cancellationToken:));
/*!
Identical to continueWithExecutor:withBlock:, except that the block
is only run if this task did not produce a cancellation, error, or an error.
If it did, then the failure will be propagated to the returned task.
@param executor A OBSBFExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithExecutor:(OBSBFExecutor *)executor
withSuccessBlock:(OBSBFContinuationBlock)block NS_SWIFT_NAME(continueOnSuccessWith(executor:block:));
/*!
Identical to continueWithExecutor:withBlock:, except that the block
is only run if this task did not produce a cancellation or an error.
If it did, then the failure will be propagated to the returned task.
@param executor A OBSBFExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OBSBFTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OBSBFTask *)continueWithExecutor:(OBSBFExecutor *)executor
successBlock:(OBSBFContinuationBlock)block
cancellationToken:(nullable OBSBFCancellationToken *)cancellationToken
NS_SWIFT_NAME(continueOnSuccessWith(executor:block:cancellationToken:));
/*!
Waits until this operation is completed.
This method is inefficient and consumes a thread resource while
it's running. It should be avoided. This method logs a warning
message if it is used on the main thread.
*/
- (void)waitUntilFinished;
@end
NS_ASSUME_NONNULL_END
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class OBSBFTask<__covariant ResultType>;
/*!
A OBSBFTaskCompletionSource represents the producer side of tasks.
It is a task that also has methods for changing the state of the
task by settings its completion values.
*/
@interface OBSBFTaskCompletionSource<__covariant ResultType> : NSObject
/*!
Creates a new unfinished task.
*/
+ (instancetype)taskCompletionSource;
/*!
The task associated with this TaskCompletionSource.
*/
@property (nonatomic, strong, readonly) OBSBFTask<ResultType> *task;
/*!
Completes the task by setting the result.
Attempting to set this for a completed task will raise an exception.
@param result The result of the task.
*/
- (void)setResult:(nullable ResultType)result NS_SWIFT_NAME(set(result:));
/*!
Completes the task by setting the error.
Attempting to set this for a completed task will raise an exception.
@param error The error for the task.
*/
- (void)setError:(NSError *)error NS_SWIFT_NAME(set(error:));
/*!
Completes the task by marking it as cancelled.
Attempting to set this for a completed task will raise an exception.
*/
- (void)cancel;
/*!
Sets the result of the task if it wasn't already completed.
@returns whether the new value was set.
*/
- (BOOL)trySetResult:(nullable ResultType)result NS_SWIFT_NAME(trySet(result:));
/*!
Sets the error of the task if it wasn't already completed.
@param error The error for the task.
@returns whether the new value was set.
*/
- (BOOL)trySetError:(NSError *)error NS_SWIFT_NAME(trySet(error:));
/*!
Sets the cancellation state of the task if it wasn't already completed.
@returns whether the new value was set.
*/
- (BOOL)trySetCancelled;
@end
NS_ASSUME_NONNULL_END
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSBaseCategory_h
#define OBSBaseCategory_h
#import "OBSBaseConstDefinition.h"
#import "OBSMTLJSONAdapter.h"
#import "OBSMTLValueTransformer.h"
@class OBSBaseNetworkingRequest;
@class OBSBFTaskCompletionSource;
@interface NSString (OBS)
//data to NSString with utf8 encoding
+ (nullable instancetype)obs_initWithDataUTF8:(NSData *)data;
//OBSHTTPMethod enum to string
+ (nullable instancetype)obs_initWithOBSHTTPMethod:(OBSHTTPMethod) HTTPMethod;
//url string remove tailing slash
- (nullable NSString*)obs_removeTailSlash;
//url string append query string
//- (nullable NSString*)obs_stringByAppendingQueryStringForURL:(NSDictionary *)queryDict;
//trim spaces
- (nullable NSString*)obs_trim;
-(nullable NSString*)stringWithRepeatTimes:(NSInteger) times;
//bool with string
//-(BOOL) obs_boolWithString;
//OBSHTTPMethod string to enum
//- (OBSHTTPMethod)obs_OBSHTTPMethodWithString;
//OBSBodyType string to enum
//-(OBSBodyType)obs_OBSBodyTypeWithString;
//URL encoding
-(nullable NSString*)obs_stringWithURLEncodingAllowedSet;
//-(nullable NSString*)obs_stringWithURLEncodingAll;
//-(nullable NSString*)obs_stringWithURLEncodingAllowedAlphanumeric;
//string substitue
-(nullable NSString*)obs_stringSubstituteWithDict:(NSDictionary*) dict;
//xml encoding
//-(nullable NSString*)obs_XMLEncodeString;
@end
@interface NSDictionary(OBS)
//-(NSString*)obs_convertDictionaryToXMLWithStartNode:(NSString*)startNode;
-(NSString*)obs_XMLString;
- (NSString *)obs_innerXML:(NSInteger) ident;
- (nullable NSDictionary *)obs_childNodes;
- (nullable NSDictionary<NSString *, NSString *> *)obs_attributes;
@end
@interface NSMutableArray(OBS)
-(id)pop;
-(void)push:(id)obj;
@end
@interface NSURLSessionTask(OBS)
-(OBSBaseNetworkingRequest*)obsNetworkingRequest;
-(void)setObsNetworkingRequest:(OBSBaseNetworkingRequest*) networkingRequest;
@end
@interface OBSMTLJSONAdapter(OBS)
+ (NSDictionary *)valueTransformersForModelClass:(Class)modelClass;
@end
@interface OBSMTLValueTransformer(OBS)
//+(NSValueTransformer*)obs_mtl_nsnumberIntegerTransformer;
+(NSValueTransformer*)obs_mtl_nsnumberLongLongTransformer;
+(NSValueTransformer*)obs_mtl_nsnumberUIntegerTransformer;
+(NSValueTransformer*)obs_mtl_nsdateRFC1123Transformer;
+(NSValueTransformer*)obs_mtl_nsdateIOS8601Format3Transformer;
//+(NSValueTransformer*)obs_mtl_filterNullStringTransformer;
@end
#endif /* OBSBaseCategory_h */
... ...
//
// OBSBaseConstDefinition.h
// OBS
//
// Created by MaxZhang on 10/10/2017.
// Copyright © 2017 obs. All rights reserved.
//
#ifndef OBSBaseDefinition_h
#define OBSBaseDefinition_h
static NSString *const OBSSDKVersion =@"3.24.4";
static NSUInteger const maxConcurrentRequestCountDefault =3;
static NSString *const OBSURLReservedCharacters =@"-_.~!*'();:=@&=+$,/?#[]%";
static NSString *const OBSURLAllowedSpecialCharacters =@"-_.";
static NSString *const OBSAbstractClassPrefix =@"OBSAbstract";
#pragma mark - Errors messages;
static NSString *const OBSClientErrorDomain =@"com.obs.clientError";
static NSString *const OBSServerErrorDomain =@"com.obs.serverError";
static NSString *const OBSErrorMessageTOKEN =@"ErrorMessage";
static NSString *const OBSClientErrorHTTPRequestIDKey =@"RequestID";
static NSString *const OBSClientErrorHTTPCodeKey =@"HTTPErrorCode";
static NSString *const OBSClientErrorHTTPBodyKey =@"HTTPErrorBody";
static NSString *const OBSClientErrorInvalidParameter =@"InvalidParameter";
static char *const OBSProcessorsQueueName ="com.obs.sdk.processors";
static NSString *const OBSMaxConcurrentCommandRequestCountKey =@"maxConcurrentCommandRequestCount";
static NSString *const OBSMaxConcurrentUploadRequestCountKey =@"maxConcurrentUploadRequestCount";
static NSString *const OBSMaxConcurrentDownloadRequestCountKey =@"maxConcurrentDownloadRequestCount";
static NSString *const OBSUploadBackgroundIdentifierDefault =@"com.obs.sdk.upload";
static NSString *const OBSDownloadBackgroundIdentifierDefault =@"com.obs.sdk.download";
//networking request definition dict keys;
//common fields;
static NSString *const OBSRequestTypeKey =@"requestType";
static NSString *const OBSRequestIDKey =@"requestID";
static NSString *const OBSRequestHTTPMethodKey =@"requestMethod";
static NSString *const OBSRequestResourceStringKey =@"requestResourceString";
static NSString *const OBSRequestResourceParametersKey =@"requestResourceParameters";
static NSString *const OBSRequestQueryParametersKey =@"requestQueryParameters";
static NSString *const OBSRequestHeaderParametersKey =@"requestHeadersParameters";
static NSString *const OBSRequestBodyParameterKey =@"requestBodyParameters";
static NSString *const OBSRequestAddonRequestPostProcessorsKey =@"addonRequestPostProcessorsParameters";
static NSString *const OBSRequestAddonResponsePreProcessorsKey =@"addonResponsePreProcessorsParameters";
static NSString *const OBSRequestAuthRequiredKey =@"authenticationRequired";
//upload data fields;
static NSString *const OBSRequestUploadDataKey =@"uploadData";
static NSString *const OBSRequestUploadProgressBlockKey =@"uploadProgressBlock";
//download data fields;
static NSString *const OBSRequestOnReceiveDataBlockKey =@"onReceiveDataBlock";
static NSString *const OBSRequestDownloadProgressBlockKey =@"downloadProgressBlock";
//upload and download fields;
static NSString *const OBSRequestUploadFilePathKey =@"uploadFilePath";
static NSString *const OBSRequestDownloadFilePathKey =@"downloadFilePath";
static NSString *const OBSRequestBackgroundKey =@"background";
// headesr key;
static NSString *const OBSHeadersUAKey =@"User-Agent";
static NSString *const OBSHeadersHostKey =@"Host";
static NSString *const OBSHeadersContentTypeKey =@"Content-Type";
static NSString *const OBSHeadersContentLengthKey =@"Content-Length";
static NSString *const OBSHeadersAuthorizationKey =@"Authorization";
static NSString *const OBSDefaultContentType =@"binary/octet-stream";
//date format;
static NSString *const OBSDateShortFormat =@"yyyyMMdd";
static NSString *const OBSDateRFC1123Format =@"E, dd MMM yyyy HH:mm:ss z";
static NSString *const OBSDateISO8601Format1 =@"yyyy-MM-dd'T'HH:mm:ss'Z'";
static NSString *const OBSDateISO8601Format2 =@"yyyyMMdd'T'HHmmss'Z'" ;
static NSString *const OBSDateISO8601Format3 =@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
//output keys and download temp file extention;
static NSString *const OBSOutputCodeKey =@"statusCode";
static NSString *const OBSOutputHeadersKey =@"headers";
static NSString *const OBSOutputBodyKey =@"body";
static NSString *const OBSXMLDefaultNS =@" xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"";
static NSString *const OBSXMLDefaultNS_OBS =@" xmlns=\"http://myhwclouds.com/doc/2015-06-30/\"";
static NSString *const OBSXMLDictionaryNodeOrderKey =@"__order";
#pragma mark -Enum
/**
* OBS鉴权版本枚举
*/
typedef NS_ENUM(NSInteger, OBSContentType) {
/**
* 默认类型
*/
OBSContentTypeNULL0,
/**
* mp4
*/
OBSContentTypeMP4,
/**
* 二进制流
*/
OBSContentTypeBinary,
/**
* JPEG
*/
OBSContentTypeJPEG,
/**
* PNG
*/
OBSContentTypePNG,
/**
* HTML
*/
OBSContentTypeHTML,
/**
* GIF
*/
OBSContentTypeGIF,
/**
* PDF
*/
OBSContentTypePDF,
/**
* MP3
*/
OBSContentTypeMP3,
/**
* WAV
*/
OBSContentTypeWAV,
/**
* MOV
*/
OBSContentTypeMOV,
/**
* m3u8
*/
OBSContentTypeM3U8,
};
typedef NS_ENUM(NSInteger, OBSAuthVersion) {
/**
* 默认鉴权
*/
OBSAuthVersionNULL0,
/**
* V2鉴权
*/
OBSAuthVersionV2,
/**
* V4鉴权
*/
OBSAuthVersionV4,
};
/**
* OBS协议种类
*/
typedef NS_ENUM(NSInteger, OBSProtocolType) {
/**
* 旧版本协议
*/
OBSProtocolTypeOld,
/**
* 自研协议
*/
OBSProtocolTypeOBS,
};
/**
* OBS错误码枚举
*/
typedef NS_ENUM(NSInteger, OBSErrorCode) {
/**
* 默认
*/
OBSErrorCodeNoErrorCode0,
/**
* 服务器错误
*/
OBSErrorCodeServerErrorStatus,
/**
* 客户端错误
*/
OBSErrorCodeClientErrorStatus,
};
/**
* OBS客户端错误码枚举
*/
typedef NS_ENUM(NSInteger, OBSClientErrorCODE) {
/**
* 默认
*/
OBSRequestNoErrorCode0,
/**
* 定义未找到
*/
OBSClientErrorRequestDefinitionNotFoundCode,
/**
* 响应错误码
*/
OBSClientErrorHTTPResponseCodeError,
/**
* 签名错误
*/
OBSClientErrorCodeSignFailed,
// OBSClientErrorCodeNetworkingFailWithResponseCode0,
// OBSClientErrorCodeFileCantWrite,
// OBSClientErrorCodeInvalidArgument,
// OBSClientErrorCodeNilUploadid,
// OBSClientErrorCodeTaskCancelled,
// OBSClientErrorCodeNetworkError,
// OBSClientErrorCodeCannotResumeUpload,
// OBSClientErrorCodeExcpetionCatched,
// OBSClientErrorCodeNotKnown
};
/**
* OBS请求代理类型
*/
typedef NS_ENUM(NSInteger, OBSHTTPProxyType) {
/**
* 默认
*/
OBSHTTPRroxyTypeNull0,
/**
* HTTP
*/
OBSHTTPRroxyTypeHTTP,
/**
* HTTPS
*/
OBSHTTPRroxyTypeHTTPS,
/**
* HTTP & HTTPS
*/
OBSHTTPRroxyTypeHTTPAndHTTPS,
};
/**
* 请求类型
*/
typedef NS_ENUM(NSInteger, OBSRequestType){
/**
* 默认
*/
OBSRequestTypeNull0,
/**
* 命令
*/
OBSRequestTypeCommandRequest,
/**
* 上传数据
*/
OBSRequestTypeUploadDataRequest,
/**
* 上传文件
*/
OBSRequestTypeUploadFileRequest,
/**
* 下载数据
*/
OBSRequestTypeDownloadDataRequest,
/**
* 下载文件
*/
OBSRequestTypeDownloadFileRequest,
};
/**
* 请求体内容
*/
typedef NS_ENUM(NSInteger, OBSBodyType){
/**
* 默认
*/
OBSBodyTypeNull0,
/**
* JSON
*/
OBSBodyTypeJSON,
/**
* XML
*/
OBSBodyTypeXML,
/**
* 字符串
*/
OBSBodyTypeStringData,
};
/**
* 请求方法类型枚举
*/
typedef NS_ENUM(NSInteger, OBSHTTPMethod){
OBSHTTPMethodNull0,
OBSHTTPMethodGET,
OBSHTTPMethodHEAD,
OBSHTTPMethodPUT,
OBSHTTPMethodPOST,
OBSHTTPMethodTRACE,
OBSHTTPMethodOPTIONS,
OBSHTTPMethodDELETE,
OBSHTTPMethodLOCK,
OBSHTTPMethodMKCOL,
OBSHTTPMethodMOVE,
};
#pragma mark - ignore warn
#define SuppressPerformSelectorLeakWarning(code) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
code\
_Pragma("clang diagnostic pop") \
#define SuppressMethodDefinitionNotFoundWarning(code) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wincomplete-implementation\"") \
code\
_Pragma("clang diagnostic pop") \
#define MakeDispatchOnceDictBEGIN \
static NSDictionary *dict; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{
#define MakeDispatchOnceDictEND\
}); \
#define MakeDispatchOnceArrayBEGIN \
static NSArray *array; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{
#define MakeDispatchOnceArrayEND\
}); \
#define MakeDispatchOnceTransformerBEGIN \
static NSValueTransformer *transformer; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{
#define MakeDispatchOnceTransformerEND \
}); \
#define metamacro_concat(A,B) A ## B
#define weakify(VAR) \
autoreleasepool {} \
__weak __typeof__(VAR) weak##VAR = VAR
// __weak __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR)
#define strongify(VAR) \
autoreleasepool {} \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
__strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_)\
_Pragma("clang diagnostic pop") \
#pragma mark - Progress block
typedef void (^OBSNetworkingUploadProgressBlock) (int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
typedef void (^OBSNetworkingDownloadProgressBlock) (int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
typedef void (^OBSNetworkingOnReceiveDataBlock)(NSData *data);
#endif /* OBSConstDefinition_h */
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSBaseModel_h
#define OBSBaseModel_h
#import "OBSBaseCategory.h"
#import "OBSBaseConstDefinition.h"
#import "OBSMantle.h"
#import "OBSXMLDictionary.h"
@class OBSRequestConverter;
@protocol OBSNetworkingRequestPostProcessor;
//#pragma mark - OBSSafeMutableDictionary
//@interface OBSSafeMutableDictionary<KeyType, ObjectType>:NSMutableDictionary
//- (id) objectForKey:(id)aKey;
//- (void)setObject:(ObjectType)anObject forKey:(KeyType <NSCopying>) aKey;
//- (void)removeObjectForKey:(KeyType)aKey;
//@end
//#pragma mark - OBSOrderedMutableDictionary
//@interface OBSOrderedMutableDictionary<KeyType, ObjectType>:NSMutableDictionary
//- (id) objectForKey:(id)aKey;
//- (void)setObject:(ObjectType)anObject forKey:(KeyType <NSCopying>) aKey;
//- (void)removeObjectForKey:(KeyType)aKey;
//- (NSEnumerator*)keyEnumerator;
//- (NSUInteger)count;
//@end
#pragma mark - OBSWeakMutableArray
@interface OBSWeakMutableArray<ObjectType>:NSMutableArray
-(instancetype)initWithCapacity:(NSUInteger)numItems;
-(NSUInteger)count;
-(void)addObject:(id)anObject;
-(void)removeObject:(id)anObject;
-(void)removeObjectAtIndex:(NSUInteger)index;
-(id)objectAtIndex:(NSUInteger)index;
@end
@protocol OBSGetBodyTypeProtocol<NSObject>
+(OBSBodyType)GetBodyType;
@end
#pragma mark configuration
@interface OBSHTTPProxyConfiguration : NSObject
@property (nonatomic, assign) OBSHTTPProxyType proxyType;
@property (nonatomic, strong, nonnull) NSString *proxyHost;
@property (nonatomic, strong, nonnull) NSNumber *proxyPort;
@property (nonatomic, strong, nonnull) NSString *username;
@property (nonatomic, strong, nonnull) NSString *password;
/**
端口代理初始化
@param proxyType 请求类型(OBSHTTPRroxyTypeNull0 OBSHTTPRroxyTypeHTTP OBSHTTPRroxyTypeHTTPS OBSHTTPRroxyTypeHTTPAndHTTPS)
@param host host
@param port port
@return 代理对象
*/
-(instancetype)initWithType:(OBSHTTPProxyType) proxyType proxyHost:(NSString*) host proxyPort:(NSUInteger) port;
-(NSDictionary*) getProxyDict;
@end
@interface OBSBaseConfiguration : NSObject
@property (nonatomic, strong, readonly, nonnull) NSURL *url;
@property (nonatomic, strong) NSString *lastUploadPath;
@property (nonatomic, strong) NSData *uploadAllData;
@property (nonatomic, assign) BOOL trustUnsafeCert;
@property (nonatomic, assign) uint32_t maxConcurrentCommandRequestCount;
@property (nonatomic, assign) uint32_t maxConcurrentUploadRequestCount;
@property (nonatomic, assign) uint32_t maxConcurrentDownloadRequestCount;
@property (nonatomic, strong) NSURLSessionConfiguration * commandSessionConfiguration;
@property (nonatomic, strong) NSURLSessionConfiguration * uploadSessionConfiguration;
@property (nonatomic, strong) NSURLSessionConfiguration * downloadSessionConfiguration;
@property (nonatomic, strong) NSURLSessionConfiguration * backgroundUploadSessionConfiguration;
@property (nonatomic, strong) NSURLSessionConfiguration * backgroundDownloadSessionConfiguration;
@property (nonatomic, strong) OBSHTTPProxyConfiguration * proxyConfig;
@property (nonatomic, strong) NSMutableArray<id<OBSNetworkingRequestPostProcessor>> * customProcessors;
@property (nonatomic, assign) BOOL enableURLEncoding;
-(instancetype) initWithURL:(NSURL*) url;
-(NSArray*)getDefaultPostProcessors;
@end
#pragma mark MTLJSONAdaptor and XML Parser
@protocol OBSMTLDictionaryItemOrderProtocol <NSObject>
@required
+(NSArray*)DictionaryOrderList;
@end
@interface OBSMTLJSONAdapterCustomized: OBSMTLJSONAdapter
-(void)setModelClass:(Class)clazz;
-(Class)modelClass;
-(void)setJSONKeyPathsByPropertyKey:(NSDictionary*)dict;
-(NSDictionary*)JSONKeyPathsByPropertyKey;
-(void)setValueTransformersByPropertyKey:(NSDictionary*)dict;
-(NSDictionary*)valueTransformersByPropertyKey;
-(void)setJSONAdaptersByModelClass:(NSMapTable*)dict;
-(NSMapTable*)JSONAdaptersByModelClass;
- (OBSMTLJSONAdapter *)JSONAdapterForModelClass:(Class)modelClass error:(NSError **)error;
@end
@interface OBSXMLDictionaryParserWithFormat: OBSXMLDictionaryParser
+ (NSString *)OBSXMLStringForNode:(id)node withNodeName:(NSString *)nodeName ident:(NSInteger) ident;
- (void)endText;
-(void)setRoot:(NSMutableDictionary<NSString *, id>*) root;
-(NSMutableDictionary<NSString *, id>*)root;
-(void)setStack:(NSMutableArray*) stack;
-(NSMutableArray*)stack;
@end
#pragma mark - Base Model
@protocol OBSRequestConvert
@required
-(OBSBaseNetworkingRequest*)convertToNetworkingRequest:(OBSBaseConfiguration*) configuration error:(NSError**) error;
@end
@interface OBSAbstractModel : OBSMTLModel<OBSMTLJSONSerializing>
@end
@interface OBSBaseEntity: OBSAbstractModel
@end
@interface OBSResponseHeaderEntity: OBSBaseEntity
@end
@interface OBSResponseURLEntity: OBSBaseEntity
@end
@interface OBSResponseBodyEntity: OBSBaseEntity
@end
#pragma mark - Base Requests
/**
OBS网络请求基类
*/
@interface OBSBaseRequest: OBSAbstractModel<OBSRequestConvert>
/**
请求ID
*/
@property (nonatomic, strong, nonnull) NSString *requestID;
/**
是否取消
*/
@property (readonly, nonatomic, assign) BOOL isCancelled;
/**
请求类型
*/
@property (nonatomic, assign) OBSProtocolType protocolType;
/**
取消请求
*/
-(void)cancel;
/**
判断是否是一个合法的请求
@param error 抛出的错误
@return 返回是否为合法请求
*/
-(BOOL)validateRequest:(NSError**)error;
@end
#pragma mark - Base Response
/**
OBS网络响应基类
*/
@interface OBSBaseResponse: OBSAbstractModel<OBSGetBodyTypeProtocol>
/**
响应状态码
*/
@property (nonatomic, strong, nonnull) NSString *statusCode;
/**
响应头部
*/
@property (nonatomic, strong, nullable) NSDictionary *headers;
/**
请求ID
*/
@property (nonatomic, strong, nullable) NSString *requestID;
@end
#endif /* OBSBaseModel_h */
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSBaseNetworking_h
#define OBSBaseNetworking_h
#import "OBSBaseConstDefinition.h"
#import "OBSBaseModel.h"
@class OBSBFTaskCompletionSource;
@class OBSBFTask;
@class OBSBaseRequest;
@class OBSEndpoint;
@class OBSBaseNetworkingRequest;
@class OBSBaseConfiguration;
@class OBSAbstractCredentailProvider;
@protocol NSURLSessionDelegate;
@protocol NSURLSessionDataDelegate;
@protocol OBSServiceCredentialProvider;
#pragma mark - Networking classes
@protocol OBSNetworkingRequestPostProcessor<NSObject>
@required
+(void)processRequest:(OBSBaseNetworkingRequest*) request configuration:(__kindof OBSBaseConfiguration *const) configuration error:(NSError**) error;
@end
@protocol OBSNetworkingResponsePreProcessor<NSObject>
@required
+(void)processResponse:(NSMutableDictionary*) responseDict configuration:(__kindof OBSBaseConfiguration *const) configuration error:(NSError**) error;
@end
@interface OBSRequestURLStringPostProcessor: NSObject<OBSNetworkingRequestPostProcessor>
@end
@interface OBSResouceParameterPostProcessor: NSObject<OBSNetworkingRequestPostProcessor>
@end
@interface OBSHeaderUAPostProcessor: NSObject <OBSNetworkingRequestPostProcessor>
@end
@interface OBSHeaderContentLengthPostProcessor: NSObject <OBSNetworkingRequestPostProcessor>
@end
@interface OBSHeaderContentTypePostProcessor: NSObject <OBSNetworkingRequestPostProcessor>
@end
@interface OBSHeaderHostPostProcessor: NSObject <OBSNetworkingRequestPostProcessor>
@end
@interface OBSURLEncodingPostProcessor: NSObject <OBSNetworkingRequestPostProcessor>
@end
@protocol OBSNetworkingRequestJSONDataProtocol<NSObject>
@required
+(NSDictionary*) AdditionalJSONData;
+(NSDictionary*) getAdditionalJSONDataIncludeParents;
@end
#pragma mark - Networking Manager
@interface OBSNetworkingManager :NSObject<NSURLSessionDelegate, NSURLSessionTaskDelegate,NSURLSessionDataDelegate,NSURLSessionDownloadDelegate>
@property (nonatomic, readonly, nonnull) OBSBaseConfiguration *configuration;
-(instancetype) initWithConfiguration:(OBSBaseConfiguration*) configuration;
-(OBSBFTask*) sendRequest: (OBSBaseNetworkingRequest*) request;
-(void)releaseSessions;
@end
#pragma mark - networking base requests
@protocol OBSNetworkingGetResponseClazz
@optional
-(Class)getResponseClazz;
@end
@interface OBSBaseNetworkingRequest : OBSAbstractModel<OBSNetworkingGetResponseClazz>
//config
@property (nonatomic, assign) OBSRequestType requestType;
@property (nonatomic, copy, nonnull) NSString *requestID;
@property (nonatomic, assign) OBSHTTPMethod requestMethod;
@property (nonatomic, strong, nullable) NSString *requestBaseURLString;
@property (nonatomic, strong, nullable) NSString *requestResourceString;
@property (nonatomic, strong, nullable) NSString *requestOriginalResourceString;
@property (nonatomic, strong, nullable) NSMutableDictionary *requestResourceParameters;
@property (nonatomic, strong, nullable) NSMutableDictionary *requestQueryParameters;
@property (nonatomic, strong, nullable) NSMutableDictionary *requestHeadersParameters;
@property (nonatomic, strong, nullable) NSMutableArray *addonRequestPostProcessorsParameters;
@property (nonatomic, strong, nullable) NSMutableArray *addonResponsePreProcessorsParameters;
//processing attribute
@property (nonatomic, strong, nullable) NSData *requestBodyData;
@property (nonatomic, strong, nullable) NSMutableData *responseData;
@property (nonatomic, strong) NSMutableArray<Class<OBSNetworkingRequestPostProcessor>> *postProcessors;
@property (nonatomic, strong) NSMutableArray<Class<OBSNetworkingResponsePreProcessor>> *preProcessors;
@property (nonatomic, strong, nullable) OBSWeakMutableArray<NSURLSessionTask*> *sessionTaskList;
@property (nonatomic, strong) OBSBFTaskCompletionSource *completionSource;
@property (nonatomic, weak, nullable) OBSBaseRequest *obsRequest;
@property (readonly, nonatomic, assign) BOOL isCancelled;
-(void)cancel;
@end
@interface OBSNetworkingCommandRequest : OBSBaseNetworkingRequest<OBSNetworkingRequestJSONDataProtocol, OBSGetBodyTypeProtocol>
@property (nonatomic, strong, nullable) NSMutableDictionary *requestBodyParameters;
@end
@interface OBSNetworkingUploadDataRequest : OBSBaseNetworkingRequest<OBSNetworkingRequestJSONDataProtocol>
@property (nonatomic, strong, nonnull) NSData *uploadData;
@property (nonatomic, copy, nullable) OBSNetworkingUploadProgressBlock uploadProgressBlock;
@end
@interface OBSNetworkingUploadFileRequest : OBSBaseNetworkingRequest<OBSNetworkingRequestJSONDataProtocol>
@property (nonatomic, strong, nonnull) NSString *uploadFilePath;
@property (nonatomic, assign) BOOL background;
@property (nonatomic, copy, nullable) OBSNetworkingUploadProgressBlock uploadProgressBlock;
@end
@interface OBSNetworkingDownloadDataRequest : OBSBaseNetworkingRequest<OBSNetworkingRequestJSONDataProtocol>
@property (nonatomic, copy, nonnull) OBSNetworkingOnReceiveDataBlock onReceiveDataBlock;
@property (nonatomic, copy) OBSNetworkingDownloadProgressBlock downloadProgressBlock;
@property (nonatomic, assign) int64_t bytes_totalGot;
@end
@interface OBSNetworkingDownloadFileRequest : OBSBaseNetworkingRequest<OBSNetworkingRequestJSONDataProtocol>
@property (nonatomic, assign) BOOL background;
@property (nonatomic, strong, nonnull) NSString * downloadFilePath;
@property (nonatomic, copy) OBSNetworkingDownloadProgressBlock downloadProgressBlock;
@end
#endif /* OBSBaseNetworking_h */
... ...
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OBSBFCancellationToken.h"
#import "OBSBFCancellationTokenRegistration.h"
#import "OBSBFCancellationTokenSource.h"
#import "OBSBFExecutor.h"
#import "OBSBFGeneric.h"
#import "OBSBFTask.h"
#import "OBSBFTaskCompletionSource.h"
#if __has_include("OBSBFAppLink.h") && TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV
#import "OBSBFAppLink.h"
#import "OBSBFAppLinkNavigation.h"
#import "OBSBFAppLinkResolving.h"
#import "OBSBFAppLinkReturnToRefererController.h"
#import "OBSBFAppLinkReturnToRefererView.h"
#import "OBSBFAppLinkTarget.h"
#import "OBSBFMeasurementEvent.h"
#import "OBSBFURL.h"
#import "OBSBFWebViewAppLinkResolver.h"
#endif
NS_ASSUME_NONNULL_BEGIN
/**
A string containing the version of the Bolts Framework used by the current application.
*/
FOUNDATION_EXPORT NSString *const OBSBoltsFrameworkVersionString;
NS_ASSUME_NONNULL_END
... ...
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// *Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// *Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
/**
*This class represents an NSColor replacement for CLI projects that don't link with AppKit
**/
@interface OBSCLIColor : NSObject
/**
* Convenience method for creating a `OBSCLIColor` instance from RGBA params
*
* @param red red channel, between 0 and 1
* @param green green channel, between 0 and 1
* @param blue blue channel, between 0 and 1
* @param alpha alpha channel, between 0 and 1
*/
+ (OBSCLIColor *)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
/**
* Get the RGBA components from a `OBSCLIColor`
*
* @param red red channel, between 0 and 1
* @param green green channel, between 0 and 1
* @param blue blue channel, between 0 and 1
* @param alpha alpha channel, between 0 and 1
*/
- (void)getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha NS_SWIFT_NAME(get(red:green:blue:alpha:));
@end
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSClient_h
#define OBSClient_h
#import "OBSLogging.h"
@class OBSBaseRequest;
@class OBSBFTask;
@class OBSBaseConfiguration;
@class OBSRequestConverter;
@interface OBSClient:NSObject
@property (nonatomic, strong, nonnull) OBSBaseConfiguration *configuration;
#pragma mark - init
/**
client初始化
@param configuration 配置参数
@return client对象
*/
-(instancetype) initWithConfiguration: (__kindof OBSBaseConfiguration*) configuration;
#pragma mark - set logger
/* *Set log level, default level is info.
log levels are:
OBSDDLogLevelOff
OBSDDLogLevelError
OBSDDLogLevelWarning
OBSDDLogLevelInfo
OBSDDLogLevelDebug
OBSDDLogLevelVerbose
*/
/**
设置日志等级
@param logLevel 日志种类
OBSDDLogLevelOff
OBSDDLogLevelError
OBSDDLogLevelWarning
OBSDDLogLevelInfo
OBSDDLogLevelDebug
OBSDDLogLevelVerbose
*/
-(void) setLogLevel:(OBSDDLogLevel) logLevel;
/**
*Add custom logger, such as file logger
*/
/**
添加日志logger
@param logger 日志logger类型
*/
-(void) addLogger: (id <OBSDDLogger>) logger;
/**
*Set Apple System Logger on, after turnning on this log could be seeing in the system's console app.
*/
/**
开启窗口日志打印
*/
-(void) setASLogOn;
- (OBSBFTask*)invokeRequest:(OBSBaseRequest *) request;
-(BOOL)getOBSProtocol:(OBSBaseRequest *)request;
@end
#endif /* OBSClient_h */
... ...
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// *Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// *Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
/**
*Welcome to CocoaLumberjack!
*
*The project page has a wealth of documentation if you have any questions.
*https://github.com/CocoaLumberjack/CocoaLumberjack
*
*If you're new to the project you may wish to read "Getting Started" at:
*Documentation/GettingStarted.md
*
*Otherwise, here is a quick refresher.
*There are three steps to using the macros:
*
*Step 1:
*Import the header in your implementation or prefix file:
*
*#import <CocoaLumberjack/CocoaLumberjack.h>
*
*Step 2:
*Define your logging level in your implementation file:
*
// Log levels: off, error, warn, info, verbose
*static const OBSDDLogLevel obsddLogLevel = OBSDDLogLevelVerbose;
*
*Step 2 [3rd party frameworks]:
*
*Define your OBSLOG_LEVEL_DEF to a different variable/function than obsddLogLevel:
*
// #undef OBSLOG_LEVEL_DEF // Undefine first only if needed
*#define OBSLOG_LEVEL_DEF myLibLogLevel
*
*Define your logging level in your implementation file:
*
// Log levels: off, error, warn, info, verbose
*static const OBSDDLogLevel myLibLogLevel = OBSDDLogLevelVerbose;
*
*Step 3:
*Replace your NSLog statements with OBSDDLog statements according to the severity of the message.
*
*NSLog(@"Fatal error, no dohickey found!"); -> OBSDDLogError(@"Fatal error, no dohickey found!");
*
*OBSDDLog works exactly the same as NSLog.
*This means you can pass it multiple variables just like NSLog.
**/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
NS_ASSUME_NONNULL_END
FOUNDATION_EXPORT NSString *const OBSCocoaLumberjackFrameworkVersionString;
// Disable legacy macros
#ifndef OBSDD_LEGACY_MACROS
#define OBSDD_LEGACY_MACROS 0
#endif
// Core
#import "OBSDDLog.h"
// Main macros
#import "OBSDDLogMacros.h"
#import "OBSDDAssertMacros.h"
// Capture ASL
#import "OBSDDASLLogCapture.h"
// Loggers
#import "OBSDDTTYLogger.h"
#import "OBSDDASLLogger.h"
#import "OBSDDFileLogger.h"
#import "OBSDDOSLogger.h"
// CLI
#if __has_include("OBSCLIColor.h") && TARGET_OS_OSX
#import "OBSCLIColor.h"
#endif
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSCompleteMultipartUploadModel_h
#define OBSCompleteMultipartUploadModel_h
#import "OBSBaseNetworking.h"
#import "OBSClient.h"
#import "OBSServiceBaseModel.h"
#import "OBSServiceConstDefinition.h"
#import "OBSServiceCommonEntities.h"
@class OBSAbstractEncryption;
//request
#pragma mark - request
/**
合并段
*/
@protocol OBSCompleteMultipartUploadProtocol<NSObject>
@required
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
/**
对象名
*/
@property (nonatomic, strong, nonnull) NSString *objectKey;
/**
多段上传任务ID
*/
@property (nonatomic, strong, nonnull) NSString *uploadID;
/**
多段任务列表
*/
@property (nonatomic, strong, nonnull) NSMutableArray<OBSPart*> *partsList;
@end
/**
合并段request
*/
@interface OBSCompleteMultipartUploadRequest : OBSBaseRequest<OBSCompleteMultipartUploadProtocol>
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
/**
对象名
*/
@property (nonatomic, strong, nonnull) NSString *objectKey;
/**
多段上传任务ID
*/
@property (nonatomic, strong, nonnull) NSString *uploadID;
/**
多段上传对象列表
*/
@property (nonatomic, strong, nonnull) NSMutableArray<OBSPart*> *partsList;
/**
初始化合并段request
@param bucketName 桶名
@param objectKey 对象名
@param uploadID 多段上传任务ID
@return 合并段request
*/
-(instancetype)initWithBucketName:(NSString*) bucketName objectKey: (NSString*) objectKey uploadID:(NSString*) uploadID;
@end
#pragma mark - networking request
@interface OBSNetworkingCompleteMultipartUploadRequest : OBSServiceNetworkingCommandRequest
@end
//response
#pragma mark - response
/**
合并段response
*/
@interface OBSCompleteMultipartUploadResponse: OBSServiceResponse
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
/**
对象名
*/
@property (nonatomic, strong, nonnull) NSString *objectKey;
/**
区域位置
*/
@property (nonatomic, strong, nonnull) NSString *location;
/**
对象etag
*/
@property (nonatomic, strong, nonnull) NSString *etag;
/**
多版本ID
*/
@property (nonatomic, strong, nonnull) NSString *versionID;
/**
加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *encryption;
@end
//client method
#pragma mark - client method
@interface OBSClient(completeMultipartUpload)
/**
合并段
@param request 合并段request
@param completionHandler 合并段回调
@return OBSBFTask
*/
- (OBSBFTask*)completeMultipartUpload:(__kindof OBSBaseRequest<OBSCompleteMultipartUploadProtocol>*)request
completionHandler:(void (^)(OBSCompleteMultipartUploadResponse * response, NSError * error))completionHandler;
@end
#endif /* OBSCompleteMultipartUploadModel_h */
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSCopyObjectModel_h
#define OBSCopyObjectModel_h
#import "OBSBaseNetworking.h"
#import "OBSClient.h"
#import "OBSServiceBaseModel.h"
#import "OBSServiceConstDefinition.h"
@class OBSEncryptionTypeCustomer;
@class OBSAbstractEncryption;
//request
#pragma mark - request
/**
复制对象
*/
@protocol OBSCopyObjectProtocol<NSObject>
@required
/**
被复制桶名
*/
@property (nonatomic, strong, nonnull) NSString *srcBucketName;
/**
被复制对象名
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectKey;
/**
被复制对版本ID
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectVersionID;
/**
复制后的桶名
*/
@property (nonatomic, strong, nonnull) NSString *dstBucketName;
/**
复制后的对象名
*/
@property (nonatomic, strong, nonnull) NSString *dstObjectKey;
/**
复制后对象访问策略
*/
@property (nonatomic, assign) OBSACLPolicy dstObjectACLPolicy;
/**
复制后对象元数据
*/
@property (nonatomic, assign) OBSMetaDirective dstObjectMetaDirective;
/**
如果etag匹配则复制
*/
@property (nonatomic, strong, nonnull) NSString *cpSrcIfETagMatch;
/**
如果etag不匹配则复制
*/
@property (nonatomic, strong, nonnull) NSString *cpSrcIfETagNoneMatch;
/**
只有当源对象在此参数指定的时间之后修改过才进行复制对象操作
*/
@property (nonatomic, strong, nonnull) NSDate *cpSrcIfModifiedSince;
/**
只有当源对象不在此参数指定的时间之后修改过才进行复制对象操作
*/
@property (nonatomic, strong, nonnull) NSDate *cpSrcIfUnmodifiedSince;
/**
复制后对象存储类型
*/
@property (nonatomic, assign) OBSStorageClass dstObjectStorageClass;
/**
复制后对象网站重定向
*/
@property (nonatomic, strong, nonnull) NSString *dstObjectWebsiteRedirectLocation;
/**
复制后对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *dstObjectEncryption;
/**
被复制对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *srcObjectEncryption;
/**
自定义元数据
*/
@property (nonatomic, strong, nullable) NSDictionary *metaDataDict;
@end
/**
复制对象request
*/
@interface OBSCopyObjectRequest: OBSBaseRequest<OBSCopyObjectProtocol>
/**
被复制桶名
*/
@property (nonatomic, strong, nonnull) NSString *srcBucketName;
/**
被复制的对象key
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectKey;
/**
被复制对象多版本ID
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectVersionID;
/**
复制后的桶名
*/
@property (nonatomic, strong, nonnull) NSString *dstBucketName;
/**
复制后的对象key
*/
@property (nonatomic, strong, nonnull) NSString *dstObjectKey;
/**
复制后对象的ACL
*/
@property (nonatomic, assign) OBSACLPolicy dstObjectACLPolicy;
/**
复制后对象的元数据
*/
@property (nonatomic, assign) OBSMetaDirective dstObjectMetaDirective;
/**
只有当源对象的Etag与此参数指定的值相等时才进行复制对象操作
*/
@property (nonatomic, strong, nonnull) NSString *cpSrcIfETagMatch;
/**
只有当源对象的Etag与此参数指定的值不相等时才进行复制对象操作
*/
@property (nonatomic, strong, nonnull) NSString *cpSrcIfETagNoneMatch;
/**
只有当源对象在此参数指定的时间之后修改过才进行复制对象操作
*/
@property (nonatomic, strong, nonnull) NSDate *cpSrcIfModifiedSince;
/**
只有当源对象在此参数指定的时间之后没有修改过才进行复制对象操作
*/
@property (nonatomic, strong, nonnull) NSDate *cpSrcIfUnmodifiedSince;
/**
对象存储类型
*/
@property (nonatomic, assign) OBSStorageClass dstObjectStorageClass;
/**
对象重定向
*/
@property (nonatomic, strong, nonnull) NSString *dstObjectWebsiteRedirectLocation;
/**
复制后的对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *dstObjectEncryption;
/**
被复制对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *srcObjectEncryption;
/**
自定义元数据
*/
@property (nonatomic, strong, nullable) NSDictionary *metaDataDict;
/**
自定义MIME类型
*/
@property (nonatomic, strong, nonnull) NSString *customContentType;
/**
初始化复制对象request
@param srcBucketName 被复制桶名
@param srcObjectKey 被复制对象的key
@param dstBucketName 复制后的桶名
@param dstObjectKey 复制后对象的key
@return 复制对象request
*/
-(instancetype)initWithSrcBucketName:(NSString*) srcBucketName
srcObjectKey:(NSString*) srcObjectKey
dstBucketName:(NSString*) dstBucketName
dstObjectKey:(NSString*) dstObjectKey;
@end
#pragma mark - networking request
@interface OBSNetworkingCopyObjectRequest : OBSServiceNetworkingCommandRequest
@end
//response
#pragma mark - response
/**
复制对象response
*/
@interface OBSCopyObjectResponse: OBSServiceResponse
/**
复制后对象etag值
*/
@property (nonatomic, strong, nonnull) NSString *etag;
/**
对象最后修改时间
*/
@property (nonatomic, strong, nonnull) NSDate *lastModified;
/**
如果桶多版本开启,则返回被复制对象的版本号
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectVersionID;
/**
如果桶多版本开启,则返回新对象的版本号
*/
@property (nonatomic, strong, nonnull) NSString *dstObjectVersionID;
/**
新对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *encryption;
@end
//client method
#pragma mark - client method
@interface OBSClient(copyObject)
/**
复制对象
@param request 复制对象request
@param completionHandler 复制对象回调
@return OBSBFTask
*/
- (OBSBFTask*)copyObject:(__kindof OBSBaseRequest<OBSCopyObjectProtocol>*)request
completionHandler:(void (^)(OBSCopyObjectResponse * response, NSError * error))completionHandler;
@end
#endif /* OBSCopyObjectModel_h */
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSCopyPartModel_h
#define OBSCopyPartModel_h
#import "OBSBaseNetworking.h"
#import "OBSClient.h"
#import "OBSServiceBaseModel.h"
#import "OBSServiceConstDefinition.h"
@class OBSEncryptionTypeCustomer;
@class OBSAbstractEncryption;
//request
#pragma mark - request
/**
拷贝段
*/
@protocol OBSCopyPartProtocol<NSObject>
@required
/**
被复制桶名
*/
@property (nonatomic, strong, nonnull) NSString *srcBucketName;
/**
被复制对象名
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectKey;
/**
被复制多版本ID
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectVersionID;
/**
被复制范围
*/
@property (nonatomic, strong, nonnull) NSString *range;
/**
上传段的桶名
*/
@property (nonatomic, strong, nonnull) NSString *uploadBucketName;
/**
上传段对象名
*/
@property (nonatomic, strong, nonnull) NSString *uploadObjectKey;
/**
上传段段号
*/
@property (nonatomic, strong, nonnull) NSNumber *uploadPartNumber;
/**
多段上传任务ID
*/
@property (nonatomic, strong, nonnull) NSString *uploadID;
/**
被复制对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *srcObjectEncryption;
/**
复制后对象加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *uploadEncryption;
@end
/**
拷贝段
*/
@interface OBSCopyPartRequest: OBSBaseRequest<OBSCopyPartProtocol>
/**
被拷贝桶名
*/
@property (nonatomic, strong, nonnull) NSString *srcBucketName;
/**
被拷贝的对象KEY
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectKey;
/**
被拷贝的对象多版本ID
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectVersionID;
/**
被拷贝的字节范围
*/
@property (nonatomic, strong, nonnull) NSString *range;
/**
拷贝后桶名
*/
@property (nonatomic, strong, nonnull) NSString *uploadBucketName;
/**
拷贝后对象KEY
*/
@property (nonatomic, strong, nonnull) NSString *uploadObjectKey;
/**
被拷贝的段号
*/
@property (nonatomic, strong, nonnull) NSNumber *uploadPartNumber;
/**
多段上传任务ID
*/
@property (nonatomic, strong, nonnull) NSString *uploadID;
/**
被拷贝加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *srcObjectEncryption;
/**
拷贝后加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *uploadEncryption;
/**
初始化拷贝段request
@param srcBucketName 原始桶名
@param srcObjectKey 原始对象KEY
@param uploadBucketName 拷贝后桶名
@param uploadObjectKey 拷贝后对象KEY
@param uploadPartNumber 拷贝段段号
@param uploadID 多段上传任务ID
@return 拷贝段request
*/
-(instancetype)initWithSrcBucketName:(NSString*) srcBucketName
srcObjectKey:(NSString*) srcObjectKey
uploadBucketName:(NSString*) uploadBucketName
uploadObjectKey:(NSString*) uploadObjectKey
uploadPartNumber:(NSNumber*) uploadPartNumber
uploadID:(NSString*) uploadID;
@end
#pragma mark - networking request
@interface OBSNetworkingCopyPartRequest : OBSServiceNetworkingCommandRequest
@end
//response
#pragma mark - response
/**
拷贝段response
*/
@interface OBSCopyPartResponse: OBSServiceResponse
/**
新段的etag
*/
@property (nonatomic, strong, nonnull) NSString *etag;
/**
最后修改时间
*/
@property (nonatomic, strong, nonnull) NSDate *lastModified;
/**
被拷贝对象的多版本ID
*/
@property (nonatomic, strong, nonnull) NSString *srcObjectVersionID;
/**
加密方式
*/
@property (nonatomic, strong, nonnull) __kindof OBSAbstractEncryption *encryption;
@end
//client method
#pragma mark - client method
@interface OBSClient(copyPart)
/**
拷贝段
@param request 拷贝段request
@param completionHandler 拷贝段回调
@return OBSBFTask
*/
- (OBSBFTask*)copyPart:(__kindof OBSBaseRequest<OBSCopyPartProtocol>*)request
completionHandler:(void (^)(OBSCopyPartResponse * response, NSError * error))completionHandler;
@end
#endif /* OBSCopyPartModel_h */
... ...
// Copyright 2019 Huawei Technologies Co.,Ltd.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef OBSCreateBucketModel_h
#define OBSCreateBucketModel_h
#import "OBSBaseModel.h"
#import "OBSBaseNetworking.h"
#import "OBSClient.h"
#import "OBSServiceBaseModel.h"
#import "OBSServiceConstDefinition.h"
#import "OBSServiceCommonEntities.h"
#import "OBSServiceCredentialProvider.h"
//request
#pragma mark - request entity
#pragma mark - request
/**
创建桶的
*/
@protocol OBSCreateBucketProtocol
@required
/**
桶名
*/
@property (nonatomic, strong, nonnull) NSString *bucketName;
@end
/**
创建桶request
*/
@interface OBSCreateBucketRequest: OBSBaseRequest<OBSCreateBucketProtocol>
/**
//区域配置
*/
@property (nonatomic, strong, nullable) OBSBucketConfiguration *configuration;
/**
ACL设置
OBSACLPolicyNULL0,
OBSACLPolicyPrivate,
OBSACLPolicyPublicRead,
OBSACLPolicyPublicReadWrite,
OBSACLPolicyAuthenticatedRead,
OBSACLPolicyBucketOwnerRead,
OBSACLPolicyBucketOwnerFullControl,
OBSACLPolicyLogDeliveryWrite,
*/
@property (nonatomic, assign) OBSACLPolicy bucketACLPolicy;
/**
桶存储类型
OBSStorageClassNULL0,
OBSStorageClassStandard,
OBSStorageClassStandardIA,
OBSStorageClassGlacier,
*/
@property (nonatomic, assign) OBSStorageClass defaultStorageClass;
@property (nonatomic, strong, nonnull) NSString *bucketName;
//**********************自研协议*******************************
/**
授权给指定domain下的所有用户有READ权限。
*/
@property (nonatomic, strong, nonnull) NSString *grantRead;
/**
授权给指定domain下的所有用户有WRITE权限。
*/
@property (nonatomic, strong, nonnull) NSString *grantWrite;
/**
授权给指定domain下的所有用户有READ_ACP权限。
*/
@property (nonatomic, strong, nonnull) NSString *grantReadAcp;
/**
授权给指定domain下的所有用户有WRITE_ACP权限,允许修改桶的ACL信息。
*/
@property (nonatomic, strong, nonnull) NSString *grantWriteAcp;
/**
授权给指定domain下的所有用户有FULL_CONTROL权限。
*/
@property (nonatomic, strong, nonnull) NSString *grantfullControl;
/**
授权给指定domain下的所有用户有READ权限,并且在默认情况下,该READ权限将传递给桶内所有对象。
*/
@property (nonatomic, strong, nonnull) NSString *grantreadDelivered;
/**
授权给指定domain下的所有用户有FULL_CONTROL权限,并且在默认情况下,该FULL_CONTROL权限将传递给桶内所有对象。
*/
@property (nonatomic, strong, nonnull) NSString *grantfullControlDelivered;
/**
初始化创建桶的request对象
@param bucketName 桶名
@return request实例
*/
-(instancetype)initWithBucketName:(NSString*) bucketName;
@end
#pragma mark - networking request
@interface OBSCreateBucketRequestNetworking : OBSServiceNetworkingCommandRequest
@end
//response
#pragma mark - response
/**
创建桶response
*/
@interface OBSCreateBucketResponse: OBSServiceResponse
/**
桶区域位置
*/
@property (nonatomic, strong, nullable) NSString *location;
@end
#pragma mark - client method
@interface OBSClient(createBucket)
/**
创建桶
@param request 创建桶的request对象
@param completionHandler 创建桶的回调
@return task对象
*/
- (OBSBFTask*)createBucket:(__kindof OBSBaseRequest<OBSCreateBucketProtocol>*)request
completionHandler:(void (^)(OBSCreateBucketResponse * response, NSError * error))completionHandler;
@end
#endif /* OBSServiceBaseModel_h */
... ...
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// *Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// *Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import "OBSDDASLLogger.h"
@protocol OBSDDLogger;
/**
* This class provides the ability to capture the ASL (Apple System Logs)
*/
@interface OBSDDASLLogCapture : NSObject
/**
* Start capturing logs
*/
+ (void)start;
/**
* Stop capturing logs
*/
+ (void)stop;
/**
* The current capture level.
* @note Default log level: OBSDDLogLevelVerbose (i.e. capture all ASL messages).
*/
@property (class) OBSDDLogLevel captureLevel;
@end
... ...
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// *Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// *Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef OBSDD_LEGACY_MACROS
#define OBSDD_LEGACY_MACROS 0
#endif
#import "OBSDDLog.h"
// Custom key set on messages sent to ASL
extern const char *const kOBSDDASLKeyOBSDDLog;
// Value set for kOBSDDASLKeyOBSDDLog
extern const char *const kOBSDDASLOBSDDLogValue;
/**
*This class provides a logger for the Apple System Log facility.
*
*As described in the "Getting Started" page,
*the traditional NSLog() function directs its output to two places:
*
*- Apple System Log
*- StdErr (if stderr is a TTY) so log statements show up in Xcode console
*
*To duplicate NSLog() functionality you can simply add this logger and a tty logger.
*However, if you instead choose to use file logging (for faster performance),
*you may choose to use a file logger and a tty logger.
**/
@interface OBSDDASLLogger : OBSDDAbstractLogger <OBSDDLogger>
/**
* Singleton method
*
* @return the shared instance
*/
@property (class, readonly, strong) OBSDDASLLogger *sharedInstance;
// Inherited from OBSDDAbstractLogger
// - (id <OBSDDLogFormatter>)logFormatter;
// - (void)setLogFormatter:(id <OBSDDLogFormatter>)formatter;
@end
... ...
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// *Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// *Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef OBSDD_LEGACY_MACROS
#define OBSDD_LEGACY_MACROS 0
#endif
#import "OBSDDLog.h"
/**
*This class provides an abstract implementation of a database logger.
*
*That is, it provides the base implementation for a database logger to build atop of.
*All that is needed for a concrete database logger is to extend this class
*and override the methods in the implementation file that are prefixed with "db_".
**/
@interface OBSDDAbstractDatabaseLogger : OBSDDAbstractLogger {
@protected
NSUInteger _saveThreshold;
NSTimeInterval _saveInterval;
NSTimeInterval _maxAge;
NSTimeInterval _deleteInterval;
BOOL _deleteOnEverySave;
BOOL _saveTimerSuspended;
NSUInteger _unsavedCount;
dispatch_time_t _unsavedTime;
dispatch_source_t _saveTimer;
dispatch_time_t _lastDeleteTime;
dispatch_source_t _deleteTimer;
}
/**
*Specifies how often to save the data to disk.
*Since saving is an expensive operation (disk io) it is not done after every log statement.
*These properties allow you to configure how/when the logger saves to disk.
*
*A save is done when either (whichever happens first):
*
*- The number of unsaved log entries reaches saveThreshold
*- The amount of time since the oldest unsaved log entry was created reaches saveInterval
*
*You can optionally disable the saveThreshold by setting it to zero.
*If you disable the saveThreshold you are entirely dependent on the saveInterval.
*
*You can optionally disable the saveInterval by setting it to zero (or a negative value).
*If you disable the saveInterval you are entirely dependent on the saveThreshold.
*
*It's not wise to disable both saveThreshold and saveInterval.
*
*The default saveThreshold is 500.
*The default saveInterval is 60 seconds.
**/
@property (assign, readwrite) NSUInteger saveThreshold;
/**
* See the description for the `saveThreshold` property
*/
@property (assign, readwrite) NSTimeInterval saveInterval;
/**
*It is likely you don't want the log entries to persist forever.
*Doing so would allow the database to grow infinitely large over time.
*
*The maxAge property provides a way to specify how old a log statement can get
*before it should get deleted from the database.
*
*The deleteInterval specifies how often to sweep for old log entries.
*Since deleting is an expensive operation (disk io) is is done on a fixed interval.
*
*An alternative to the deleteInterval is the deleteOnEverySave option.
*This specifies that old log entries should be deleted during every save operation.
*
*You can optionally disable the maxAge by setting it to zero (or a negative value).
*If you disable the maxAge then old log statements are not deleted.
*
*You can optionally disable the deleteInterval by setting it to zero (or a negative value).
*
*If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted.
*
*It's not wise to enable both deleteInterval and deleteOnEverySave.
*
*The default maxAge is 7 days.
*The default deleteInterval is 5 minutes.
*The default deleteOnEverySave is NO.
**/
@property (assign, readwrite) NSTimeInterval maxAge;
/**
* See the description for the `maxAge` property
*/
@property (assign, readwrite) NSTimeInterval deleteInterval;
/**
* See the description for the `maxAge` property
*/
@property (assign, readwrite) BOOL deleteOnEverySave;
/**
*Forces a save of any pending log entries (flushes log entries to disk).
**/
- (void)savePendingLogEntries;
/**
*Removes any log entries that are older than maxAge.
**/
- (void)deleteOldLogEntries;
@end
... ...
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// *Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// *Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
/**
*NSAsset replacement that will output a log message even when assertions are disabled.
**/
#define OBSDDAssert(condition, frmt, ...) \
if (!(condition)) { \
NSString *description = [NSString stringWithFormat:frmt, ## __VA_ARGS__]; \
OBSDDLogError(@"%@", description); \
NSAssert(NO, description); \
}
#define OBSDDAssertCondition(condition) OBSDDAssert(condition, @"Condition not satisfied: %s", #condition)
... ...
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// *Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// *Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef OBSDD_LEGACY_MACROS
#define OBSDD_LEGACY_MACROS 0
#endif
#import "OBSDDLog.h"
/**
*This class provides a log formatter that filters log statements from a logging context not on the whitelist.
*
*A log formatter can be added to any logger to format and/or filter its output.
*You can learn more about log formatters here:
*Documentation/CustomFormatters.md
*
*You can learn more about logging context's here:
*Documentation/CustomContext.md
*
*But here's a quick overview / refresher:
*
*Every log statement has a logging context.
*These come from the underlying logging macros defined in OBSDDLog.h.
*The default logging context is zero.
*You can define multiple logging context's for use in your application.
*For example, logically separate parts of your app each have a different logging context.
*Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context.
**/
@interface OBSDDContextWhitelistFilterLogFormatter : NSObject <OBSDDLogFormatter>
/**
* Designated default initializer
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Add a context to the whitelist
*
* @param loggingContext the context
*/
- (void)addToWhitelist:(NSUInteger)loggingContext;
/**
* Remove context from whitelist
*
* @param loggingContext the context
*/
- (void)removeFromWhitelist:(NSUInteger)loggingContext;
/**
* Return the whitelist
*/
@property (readonly, copy) NSArray<NSNumber *> *whitelist;
/**
* Check if a context is on the whitelist
*
* @param loggingContext the context
*/
- (BOOL)isOnWhitelist:(NSUInteger)loggingContext;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
*This class provides a log formatter that filters log statements from a logging context on the blacklist.
**/
@interface OBSDDContextBlacklistFilterLogFormatter : NSObject <OBSDDLogFormatter>
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Add a context to the blacklist
*
* @param loggingContext the context
*/
- (void)addToBlacklist:(NSUInteger)loggingContext;
/**
* Remove context from blacklist
*
* @param loggingContext the context
*/
- (void)removeFromBlacklist:(NSUInteger)loggingContext;
/**
* Return the blacklist
*/
@property (readonly, copy) NSArray<NSNumber *> *blacklist;
/**
* Check if a context is on the blacklist
*
* @param loggingContext the context
*/
- (BOOL)isOnBlacklist:(NSUInteger)loggingContext;
@end
... ...