@cloudcare/cocos-sdk 0.1.0-alpha.2 → 0.1.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/cli.cjs +3 -0
- package/components/creator2/ReplayPrivacy.ts +23 -0
- package/components/creator3/ReplayPrivacy.ts +25 -0
- package/dist/creator2/core/client.d.ts +1 -1
- package/dist/creator2/core/client.js +6 -6
- package/dist/creator2/core/client.js.map +1 -1
- package/dist/creator2/core/replay-async-transport.d.ts +4 -0
- package/dist/creator2/core/replay-async-transport.d.ts.map +1 -0
- package/dist/creator2/core/replay-async-transport.js +67 -0
- package/dist/creator2/core/replay-async-transport.js.map +1 -0
- package/dist/creator2/core/replay-file.d.ts +5 -0
- package/dist/creator2/core/replay-file.d.ts.map +1 -0
- package/dist/creator2/core/replay-file.js +101 -0
- package/dist/creator2/core/replay-file.js.map +1 -0
- package/dist/creator2/core/replay-privacy-nodes.d.ts +14 -0
- package/dist/creator2/core/replay-privacy-nodes.d.ts.map +1 -0
- package/dist/creator2/core/replay-privacy-nodes.js +18 -0
- package/dist/creator2/core/replay-privacy-nodes.js.map +1 -0
- package/dist/creator2/core/replay.d.ts +5 -3
- package/dist/creator2/core/replay.d.ts.map +1 -1
- package/dist/creator2/core/replay.js +77 -44
- package/dist/creator2/core/replay.js.map +1 -1
- package/dist/creator2/core/transport.d.ts +1 -0
- package/dist/creator2/core/transport.d.ts.map +1 -1
- package/dist/creator2/core/transport.js.map +1 -1
- package/dist/creator2/core/version.d.ts +1 -1
- package/dist/creator2/core/version.js +1 -1
- package/dist/creator2/creator2/capture.d.ts +1 -1
- package/dist/creator2/creator2/capture.d.ts.map +1 -1
- package/dist/creator2/creator2/capture.js +9 -16
- package/dist/creator2/creator2/capture.js.map +1 -1
- package/dist/creator2/creator2/transport.d.ts +1 -0
- package/dist/creator2/creator2/transport.d.ts.map +1 -1
- package/dist/creator2/creator2/transport.js +4 -0
- package/dist/creator2/creator2/transport.js.map +1 -1
- package/dist/creator3/core/client.d.ts +1 -1
- package/dist/creator3/core/client.js +6 -6
- package/dist/creator3/core/client.js.map +1 -1
- package/dist/creator3/core/replay-async-transport.d.ts +4 -0
- package/dist/creator3/core/replay-async-transport.d.ts.map +1 -0
- package/dist/creator3/core/replay-async-transport.js +16 -0
- package/dist/creator3/core/replay-async-transport.js.map +1 -0
- package/dist/creator3/core/replay-file.d.ts +5 -0
- package/dist/creator3/core/replay-file.d.ts.map +1 -0
- package/dist/creator3/core/replay-file.js +31 -0
- package/dist/creator3/core/replay-file.js.map +1 -0
- package/dist/creator3/core/replay-privacy-nodes.d.ts +14 -0
- package/dist/creator3/core/replay-privacy-nodes.d.ts.map +1 -0
- package/dist/creator3/core/replay-privacy-nodes.js +15 -0
- package/dist/creator3/core/replay-privacy-nodes.js.map +1 -0
- package/dist/creator3/core/replay.d.ts +5 -3
- package/dist/creator3/core/replay.d.ts.map +1 -1
- package/dist/creator3/core/replay.js +26 -12
- package/dist/creator3/core/replay.js.map +1 -1
- package/dist/creator3/core/transport.d.ts +1 -0
- package/dist/creator3/core/transport.d.ts.map +1 -1
- package/dist/creator3/core/transport.js.map +1 -1
- package/dist/creator3/core/version.d.ts +1 -1
- package/dist/creator3/core/version.js +1 -1
- package/dist/creator3/creator3/capture.d.ts +1 -1
- package/dist/creator3/creator3/capture.d.ts.map +1 -1
- package/dist/creator3/creator3/capture.js +6 -13
- package/dist/creator3/creator3/capture.js.map +1 -1
- package/dist/creator3/creator3/transport.d.ts +1 -0
- package/dist/creator3/creator3/transport.d.ts.map +1 -1
- package/dist/creator3/creator3/transport.js +4 -0
- package/dist/creator3/creator3/transport.js.map +1 -1
- package/extensions/creator2/install-native.cjs +54 -2
- package/extensions/creator3/install-native.cjs +54 -2
- package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridge.java +4 -0
- package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosReplayImageJobs.java +55 -0
- package/native/ios/FTCocosBridge.m +17 -0
- package/native/ios/FTCocosBridge.podspec +2 -2
- package/native/ios/FTCocosReplayImageJobs.h +11 -0
- package/native/ios/FTCocosReplayImageJobs.m +54 -0
- package/native/shared/FTReplayFileBridge.h +62 -0
- package/native/shared/FTReplayFileWorker.h +88 -0
- package/package.json +2 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Pod::Spec.new do |s|
|
|
2
2
|
s.name = 'FTCocosBridge'
|
|
3
|
-
s.version = '0.1.0-alpha.
|
|
3
|
+
s.version = '0.1.0-alpha.4'
|
|
4
4
|
s.summary = 'CloudCare Mobile SDK native bridge for Cocos Creator.'
|
|
5
5
|
s.homepage = 'https://github.com/GuanceCloud/datakit-cocos'
|
|
6
6
|
s.license = { :type => 'Apache-2.0' }
|
|
7
7
|
s.author = { 'Guance Cloud' => 'support@guance.com' }
|
|
8
8
|
s.source = { :path => '.' }
|
|
9
9
|
s.platform = :ios, '12.0'
|
|
10
|
-
s.source_files = 'FTCocosBridge.{h,m}'
|
|
10
|
+
s.source_files = 'FTCocosBridge.{h,m}', 'FTCocosReplayImageJobs.{h,m}'
|
|
11
11
|
s.public_header_files = 'FTCocosBridge.h'
|
|
12
12
|
s.requires_arc = true
|
|
13
13
|
# Cocos resolves FTCocosBridge by class name at runtime, so no direct symbol
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
/** One background image operation, with nonblocking result retrieval from JSB. */
|
|
6
|
+
@interface FTCocosReplayImageJobs : NSObject
|
|
7
|
+
+ (NSString *)beginWithWork:(NSString *(^)(void))work;
|
|
8
|
+
+ (NSDictionary *)poll:(NSString *)identifier;
|
|
9
|
+
@end
|
|
10
|
+
|
|
11
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#import "FTCocosReplayImageJobs.h"
|
|
2
|
+
|
|
3
|
+
@interface FTCocosReplayImageJob : NSObject
|
|
4
|
+
@property (nonatomic, copy) NSString *identifier;
|
|
5
|
+
@property (nonatomic, copy) NSString *response;
|
|
6
|
+
@end
|
|
7
|
+
@implementation FTCocosReplayImageJob
|
|
8
|
+
@end
|
|
9
|
+
|
|
10
|
+
static FTCocosReplayImageJob *currentJob;
|
|
11
|
+
|
|
12
|
+
@implementation FTCocosReplayImageJobs
|
|
13
|
+
|
|
14
|
+
+ (NSString *)beginWithWork:(NSString *(^)(void))work {
|
|
15
|
+
FTCocosReplayImageJob *job = [FTCocosReplayImageJob new];
|
|
16
|
+
job.identifier = NSUUID.UUID.UUIDString;
|
|
17
|
+
@synchronized (self) {
|
|
18
|
+
if (currentJob && !currentJob.response) {
|
|
19
|
+
[NSException raise:NSInternalInconsistencyException format:@"Replay encoder is busy"];
|
|
20
|
+
}
|
|
21
|
+
currentJob = job;
|
|
22
|
+
}
|
|
23
|
+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
|
|
24
|
+
@autoreleasepool {
|
|
25
|
+
NSString *response;
|
|
26
|
+
@try {
|
|
27
|
+
response = work();
|
|
28
|
+
} @catch (NSException *exception) {
|
|
29
|
+
NSData *data = [NSJSONSerialization dataWithJSONObject:@{
|
|
30
|
+
@"ok": @NO, @"error": exception.reason ?: @"Replay encoding failed"
|
|
31
|
+
} options:0 error:nil];
|
|
32
|
+
response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
33
|
+
}
|
|
34
|
+
@synchronized (self) {
|
|
35
|
+
job.response = response ?: @"{\"ok\":false,\"error\":\"Empty Replay encoding result\"}";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return job.identifier;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
+ (NSDictionary *)poll:(NSString *)identifier {
|
|
43
|
+
@synchronized (self) {
|
|
44
|
+
if (![currentJob.identifier isEqualToString:identifier]) {
|
|
45
|
+
[NSException raise:NSInvalidArgumentException format:@"Replay encoding job is unavailable"];
|
|
46
|
+
}
|
|
47
|
+
if (!currentJob.response) return @{ @"pending": @YES };
|
|
48
|
+
NSDictionary *result = @{ @"pending": @NO, @"response": currentJob.response };
|
|
49
|
+
currentJob = nil;
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#if __has_include("bindings/jswrapper/SeApi.h")
|
|
4
|
+
#define FT_COCOS_CREATOR3 1
|
|
5
|
+
#include "bindings/jswrapper/SeApi.h"
|
|
6
|
+
#else
|
|
7
|
+
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
|
8
|
+
#endif
|
|
9
|
+
#include "FTReplayFileWorker.h"
|
|
10
|
+
|
|
11
|
+
namespace ft_cocos {
|
|
12
|
+
|
|
13
|
+
static ReplayFileWorker replayFiles;
|
|
14
|
+
|
|
15
|
+
static bool writeReplayFile(se::State& state) {
|
|
16
|
+
const auto& args = state.args();
|
|
17
|
+
if (args.size() != 2 || !args[0].isObject() || !args[1].isString()) return false;
|
|
18
|
+
auto* object = args[0].toObject();
|
|
19
|
+
if (!object->isTypedArray()) return false;
|
|
20
|
+
uint8_t* bytes = nullptr;
|
|
21
|
+
size_t size = 0;
|
|
22
|
+
if (!object->getTypedArrayData(&bytes, &size)) return false;
|
|
23
|
+
state.rval().setBoolean(replayFiles.write(bytes, size, args[1].toString()));
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
SE_BIND_FUNC(writeReplayFile)
|
|
27
|
+
|
|
28
|
+
static bool pollReplayFile(se::State& state) {
|
|
29
|
+
state.rval().setString(replayFiles.poll());
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
SE_BIND_FUNC(pollReplayFile)
|
|
33
|
+
|
|
34
|
+
static bool removeReplayFile(se::State& state) {
|
|
35
|
+
const auto& args = state.args();
|
|
36
|
+
if (args.size() != 1 || !args[0].isString()) return false;
|
|
37
|
+
state.rval().setBoolean(replayFiles.remove(args[0].toString()));
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
SE_BIND_FUNC(removeReplayFile)
|
|
41
|
+
|
|
42
|
+
static bool registerReplayFileBridge(se::Object* global) {
|
|
43
|
+
replayFiles.cancel();
|
|
44
|
+
const se::HandleObject bridge(se::Object::createPlainObject());
|
|
45
|
+
bridge->defineFunction("write", _SE(writeReplayFile));
|
|
46
|
+
bridge->defineFunction("poll", _SE(pollReplayFile));
|
|
47
|
+
bridge->defineFunction("remove", _SE(removeReplayFile));
|
|
48
|
+
global->setProperty("__ftCocosReplayFile", se::Value(bridge));
|
|
49
|
+
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() { replayFiles.cancel(); });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static void installReplayFileBridge() {
|
|
54
|
+
#if FT_COCOS_CREATOR3
|
|
55
|
+
se::ScriptEngine::getInstance()->addPermanentRegisterCallback(registerReplayFileBridge);
|
|
56
|
+
#else
|
|
57
|
+
// Creator 2 calls AppDelegate again when restarting its script VM.
|
|
58
|
+
se::ScriptEngine::getInstance()->addRegisterCallback(registerReplayFileBridge);
|
|
59
|
+
#endif
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
} // namespace ft_cocos
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <atomic>
|
|
4
|
+
#include <cerrno>
|
|
5
|
+
#include <cstdio>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <string>
|
|
8
|
+
#include <thread>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
namespace ft_cocos {
|
|
12
|
+
|
|
13
|
+
// Accessed only by the script thread. Workers own their buffers and never touch JS.
|
|
14
|
+
class ReplayFileWorker {
|
|
15
|
+
enum Status { Pending, Written, Removed, Error };
|
|
16
|
+
struct Job {
|
|
17
|
+
std::string path;
|
|
18
|
+
std::atomic<Status> status{Pending};
|
|
19
|
+
std::atomic<bool> cancelled{false};
|
|
20
|
+
};
|
|
21
|
+
std::shared_ptr<Job> current;
|
|
22
|
+
|
|
23
|
+
public:
|
|
24
|
+
bool write(const unsigned char* bytes, size_t size, const std::string& path) {
|
|
25
|
+
if (current && current->cancelled.load() && current->status.load() != Pending) current.reset();
|
|
26
|
+
if (current || !bytes || size == 0 || size > 2048U * 2048U * 4U || path.empty()) return false;
|
|
27
|
+
try {
|
|
28
|
+
auto job = std::make_shared<Job>();
|
|
29
|
+
job->path = path;
|
|
30
|
+
// This bounded copy is necessary because the JS buffer can be collected/reused.
|
|
31
|
+
std::vector<unsigned char> pixels(bytes, bytes + size);
|
|
32
|
+
current = job;
|
|
33
|
+
std::thread([job](std::vector<unsigned char> data) {
|
|
34
|
+
FILE* file = std::fopen(job->path.c_str(), "wb");
|
|
35
|
+
bool ok = false;
|
|
36
|
+
if (file) {
|
|
37
|
+
const bool written = std::fwrite(data.data(), 1, data.size(), file) == data.size();
|
|
38
|
+
ok = std::fclose(file) == 0 && written;
|
|
39
|
+
}
|
|
40
|
+
if (!ok || job->cancelled.load()) std::remove(job->path.c_str());
|
|
41
|
+
job->status.store(ok ? Written : Error);
|
|
42
|
+
// Covers cleanup racing with the final status transition.
|
|
43
|
+
if (job->cancelled.load()) std::remove(job->path.c_str());
|
|
44
|
+
}, std::move(pixels)).detach();
|
|
45
|
+
} catch (...) {
|
|
46
|
+
current.reset();
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
bool remove(const std::string& path) {
|
|
53
|
+
if (!current || current->path != path || current->status.load() != Written) return false;
|
|
54
|
+
auto job = current;
|
|
55
|
+
job->status.store(Pending);
|
|
56
|
+
try {
|
|
57
|
+
std::thread([job]() {
|
|
58
|
+
const bool ok = std::remove(job->path.c_str()) == 0 || errno == ENOENT;
|
|
59
|
+
job->status.store(ok ? Removed : Error);
|
|
60
|
+
}).detach();
|
|
61
|
+
} catch (...) {
|
|
62
|
+
job->status.store(Written);
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const char* poll() {
|
|
69
|
+
if (!current) return "error";
|
|
70
|
+
switch (current->status.load()) {
|
|
71
|
+
case Pending: return "pending";
|
|
72
|
+
case Written: return "written";
|
|
73
|
+
case Removed: current.reset(); return "removed";
|
|
74
|
+
case Error: current.reset(); return "error";
|
|
75
|
+
}
|
|
76
|
+
return "error";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
void cancel() {
|
|
80
|
+
if (!current) return;
|
|
81
|
+
auto job = current;
|
|
82
|
+
job->cancelled.store(true);
|
|
83
|
+
if (job->status.load() == Written) remove(job->path);
|
|
84
|
+
// Keep the slot occupied until its worker exits, including across VM restarts.
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
} // namespace ft_cocos
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudcare/cocos-sdk",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
4
|
"description": "Observability SDK integration for Cocos Creator 2.4 and 3.x",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Guance Cloud",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"creator2",
|
|
38
38
|
"creator3",
|
|
39
39
|
"dist",
|
|
40
|
+
"components",
|
|
40
41
|
"extensions",
|
|
41
42
|
"native",
|
|
42
43
|
"bin",
|