forked from bnoguchi/node-hash-ring
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HashRingWrap.cc
114 lines (84 loc) · 3.22 KB
/
HashRingWrap.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "./HashRingWrap.h"
#include <map>
Napi::FunctionReference HashRingWrap::constructor;
Napi::Object HashRingWrap::Init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
Napi::Function func = DefineClass(env, "HashRing", {
InstanceMethod("getNode", &HashRingWrap::GetNode),
InstanceMethod("getBuckets", &HashRingWrap::GetBuckets)
});
constructor = Napi::Persistent(func);
constructor.SuppressDestruct();
exports.Set("HashRing", func);
return exports;
}
HashRingWrap::HashRingWrap(const Napi::CallbackInfo& info) : Napi::ObjectWrap<HashRingWrap>(info) {
const Napi::Env env = info.Env();
if (info.Length() < 1) {
Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException();
return;
}
if (!info[0].IsObject()) {
Napi::TypeError::New(env, "You must pass bucket weights as an object (property name is bucket name, property value is weight)").ThrowAsJavaScriptException();
return;
}
Napi::Object weights = info[0].As<Napi::Object>();
Napi::Array nodeNames = weights.GetPropertyNames();
unsigned int numBuckets = nodeNames.Length();
std::map<std::string, uint32_t> weightMap;
// Ensure that weight keys are strings and weight values are numbers
for (unsigned int i = 0; i < numBuckets; i++) {
Napi::Value nodeName = nodeNames.Get(i);
Napi::Value nodeValue = weights.Get(nodeName);
if (!nodeName.IsString() || !nodeValue.IsNumber()) {
Napi::TypeError::New(env, "You must pass bucket weights as an object (property name is bucket name, property value is weight)").ThrowAsJavaScriptException();
return;
}
weightMap.insert({ nodeName.ToString().Utf8Value(), nodeValue.ToNumber().Uint32Value() });
}
uint32_t precision = HashRingWrap::DEFAULT_PRECISION;
if (info.Length() > 1) {
if (info[1].IsNumber()) {
precision = info[1].As<Napi::Number>().Uint32Value();
}
if (precision <= 0) {
Napi::TypeError::New(env, "Precision must be greater than 0").ThrowAsJavaScriptException();
return;
}
}
this->hashring = new HashRing(weightMap, precision);
}
Napi::Value HashRingWrap::GetNode(const Napi::CallbackInfo& info) {
const Napi::Env env = info.Env();
if (info.Length() != 1) {
Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsString()) {
Napi::TypeError::New(env, "Only strings are supported").ThrowAsJavaScriptException();
return env.Null();
}
std::string str = info[0].As<Napi::String>().Utf8Value();
Napi::String result = Napi::String::New(env, this->hashring->GetNode(str));
return result;
}
Napi::Value HashRingWrap::GetBuckets(const Napi::CallbackInfo& info) {
const Napi::Env env = info.Env();
auto weightKeys = this->hashring->GetBuckets();
Napi::Array keys = Napi::Array::New(env, weightKeys.size());
int i = 0;
for (std::string key : weightKeys) {
keys.Set(i++, Napi::String::New(env, key));
}
return keys;
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
HashRingWrap::Init(env, exports);
return exports;
}
HashRingWrap::~HashRingWrap() {
if (this->hashring != nullptr) {
delete this->hashring;
}
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init);