1 module neton.client.registry.RegistryService;
2 
3 import neton.protocol.neton;
4 import neton.protocol.neton;
5 import neton.protocol.netonrpc;
6 
7 import grpc;
8 import hunt.logging;
9 import hunt.util.Serialize;
10 import std.conv;
11 import std.json;
12 
13 import neton.client.registry.Instance;
14 import neton.client.Listener;
15 import neton.client.WatchFactory;
16 import neton.client.Watcher;
17 import neton.client.registry.HeartBeat;
18 
19 enum HEART_TTL = 60; ///seconds
20 
21 class RegistryService
22 {
23     private
24     {
25         RegistryClient _client;
26         Watcher _watcher;
27         HeartBeat[long] _heartBeatMap;
28         Channel _channel;
29     }
30 
31     public this(Channel chanel)
32     {
33         _channel = chanel;
34         _client = new RegistryClient(chanel);
35         _watcher = WatchFactory.createRegistryWatcher(chanel, "/service");
36     }
37 
38     ~this()
39     {
40         if(_heartBeatMap.length > 0)
41         {
42             foreach(long leaseId , HeartBeat hb; _heartBeatMap) {
43                 hb.stop();
44             }
45             _heartBeatMap.clear();
46         }
47     }
48 
49     bool registerInstance(string serviceName, string ip, short port)
50     {
51         logInfo("registerInstance : ",serviceName);
52 
53         try
54         {
55             string regKey = serviceName ~ "/" ~ ip ~ ":" ~ to!string(port);
56             long leaseID = hashOf(regKey);
57             if (leaseID in _heartBeatMap)
58             {
59                 logErrorf("%s have already registered!", regKey);
60                 return false;
61             }
62             auto heartBeat = new HeartBeat(_channel);
63             heartBeat.grant(HEART_TTL, leaseID);
64 
65             Instance instant = {serviceName, ip, port};
66 
67             PutRequest request = new PutRequest();
68             request.key = cast(ubyte[])(regKey);
69             request.value = cast(ubyte[])(toJson(instant).toString);
70             request.lease = leaseID;
71             assert(request.key.length != 0);
72 
73             PutResponse response = _client.Put(request);
74             if (response is null)
75             {
76                 logError("response is null");
77                 return false;
78             }
79             _heartBeatMap[leaseID] = heartBeat;
80             heartBeat.start();
81 
82             return true;
83         }
84         catch (Throwable e)
85         {
86             logError("RegistryService : ", e.msg);
87             return false;
88         }
89     }
90 
91     bool deregisterInstance(string serviceName, string ip, short port)
92     {
93         logInfo("deregisterInstance : ",serviceName);
94         try
95         {
96             string regKey = serviceName ~ "/" ~ ip ~ ":" ~ to!string(port);
97             long leaseID = hashOf(regKey);
98 
99             DeleteRangeRequest request = new DeleteRangeRequest();
100             request.key = cast(ubyte[])(regKey);
101             assert(request.key.length != 0);
102 
103             DeleteRangeResponse response = _client.DeleteRange(request);
104             if (response is null)
105             {
106                 logError("response is null");
107                 return false;
108             }
109             if (leaseID in _heartBeatMap)
110             {
111                 _heartBeatMap[leaseID].stop();
112                 _heartBeatMap.remove(leaseID);
113             }
114             return true;
115         }
116         catch (Throwable e)
117         {
118             logError("RegistryService : ", e.msg);
119             return false;
120         }
121 
122     }
123 
124     Instance[] getAllInstances(string serviceName)
125     {
126         logInfo("getAllInstances : ",serviceName);
127         try
128         {
129             RangeRequest request = new RangeRequest();
130             request.key = cast(ubyte[]) serviceName;
131             // ubyte[] end = cast(ubyte[]) serviceName.dup;
132             // end[$ - 1] += 1;
133             // request.rangeEnd = end;
134             assert(request.key.length != 0);
135 
136             RangeResponse response = _client.Range(request);
137             if (response is null)
138             {
139                 logError("response is null");
140                 return null;
141             }
142             Instance[] values;
143             foreach (v; response.kvs)
144             {
145                 values ~= toObject!Instance(parseJSON(cast(string) v.value));
146             }
147             return values;
148         }
149         catch (Throwable e)
150         {
151             logError("RegistryService : ", e.msg);
152             return null;
153         }
154 
155     }
156 
157     void subscribe(string serviceName, Listener listener)
158     {
159         logInfo("subscribe : ",serviceName);
160         synchronized (this)
161         {
162             _watcher.watch(serviceName, listener);
163         }
164     }
165 
166     void unsubscribe(string serviceName, Listener listener)
167     {
168         logInfo("unsubscribe : ",serviceName);
169         synchronized (this)
170         {
171             _watcher.cancel(serviceName, listener);
172         }
173     }
174 
175 }