1 #include "NativeFeatureIncludes.h"
2 #if _RAKNET_SUPPORT_LogCommandParser==1
3
4 #include "LogCommandParser.h"
5 #include "TransportInterface.h"
6
7 #include <memory.h>
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdarg.h>
12
13 #include "LinuxStrings.h"
14
15 #ifdef _MSC_VER
16 #pragma warning( push )
17 #endif
18
LogCommandParser()19 LogCommandParser::LogCommandParser()
20 {
21 RegisterCommand(CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS,"Subscribe","[<ChannelName>] - Subscribes to a named channel, or all channels");
22 RegisterCommand(CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS,"Unsubscribe","[<ChannelName>] - Unsubscribes from a named channel, or all channels");
23 memset(channelNames,0,sizeof(channelNames));
24 }
~LogCommandParser()25 LogCommandParser::~LogCommandParser()
26 {
27 }
OnCommand(const char * command,unsigned numParameters,char ** parameterList,TransportInterface * transport,SystemAddress systemAddress,const char * originalString)28 bool LogCommandParser::OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, SystemAddress systemAddress, const char *originalString)
29 {
30 (void) originalString;
31
32 if (strcmp(command, "Subscribe")==0)
33 {
34 unsigned channelIndex;
35 if (numParameters==0)
36 {
37 Subscribe(systemAddress, 0);
38 transport->Send(systemAddress, "Subscribed to all channels.\r\n");
39 }
40 else if (numParameters==1)
41 {
42 if ((channelIndex=Subscribe(systemAddress, parameterList[0]))!=(unsigned)-1)
43 {
44 transport->Send(systemAddress, "You are now subscribed to channel %s.\r\n", channelNames[channelIndex]);
45 }
46 else
47 {
48 transport->Send(systemAddress, "Cannot find channel %s.\r\n", parameterList[0]);
49 PrintChannels(systemAddress, transport);
50 }
51 }
52 else
53 {
54 transport->Send(systemAddress, "Subscribe takes either 0 or 1 parameters.\r\n");
55 }
56 }
57 else if (strcmp(command, "Unsubscribe")==0)
58 {
59 unsigned channelIndex;
60 if (numParameters==0)
61 {
62 Unsubscribe(systemAddress, 0);
63 transport->Send(systemAddress, "Unsubscribed from all channels.\r\n");
64 }
65 else if (numParameters==1)
66 {
67 if ((channelIndex=Unsubscribe(systemAddress, parameterList[0]))!=(unsigned)-1)
68 {
69 transport->Send(systemAddress, "You are now unsubscribed from channel %s.\r\n", channelNames[channelIndex]);
70 }
71 else
72 {
73 transport->Send(systemAddress, "Cannot find channel %s.\r\n", parameterList[0]);
74 PrintChannels(systemAddress, transport);
75 }
76 }
77 else
78 {
79 transport->Send(systemAddress, "Unsubscribe takes either 0 or 1 parameters.\r\n");
80 }
81 }
82
83 return true;
84 }
GetName(void) const85 const char *LogCommandParser::GetName(void) const
86 {
87 return "Logger";
88 }
SendHelp(TransportInterface * transport,SystemAddress systemAddress)89 void LogCommandParser::SendHelp(TransportInterface *transport, SystemAddress systemAddress)
90 {
91 transport->Send(systemAddress, "The logger will accept user log data via the Log(...) function.\r\n");
92 transport->Send(systemAddress, "Each log is associated with a named channel.\r\n");
93 transport->Send(systemAddress, "You can subscribe to or unsubscribe from named channels.\r\n");
94 PrintChannels(systemAddress, transport);
95 }
AddChannel(const char * channelName)96 void LogCommandParser::AddChannel(const char *channelName)
97 {
98 unsigned channelIndex;
99 channelIndex = GetChannelIndexFromName(channelName);
100 // Each channel can only be added once.
101 RakAssert(channelIndex==(unsigned)-1);
102
103 unsigned i;
104 for (i=0; i < 32; i++)
105 {
106 if (channelNames[i]==0)
107 {
108 // Assuming a persistent static string.
109 channelNames[i]=channelName;
110 return;
111 }
112 }
113
114 // No more available channels - max 32 with this implementation where I save subscribed channels with bit operations
115 RakAssert(0);
116 }
WriteLog(const char * channelName,const char * format,...)117 void LogCommandParser::WriteLog(const char *channelName, const char *format, ...)
118 {
119 if (channelName==0 || format==0)
120 return;
121
122 unsigned channelIndex;
123 channelIndex = GetChannelIndexFromName(channelName);
124 if (channelIndex==(unsigned)-1)
125 {
126 AddChannel(channelName);
127 }
128
129 char text[REMOTE_MAX_TEXT_INPUT];
130 va_list ap;
131 va_start(ap, format);
132 _vsnprintf(text, REMOTE_MAX_TEXT_INPUT, format, ap);
133 va_end(ap);
134 text[REMOTE_MAX_TEXT_INPUT-1]=0;
135
136 // Make sure that text ends in \r\n
137 int textLen;
138 textLen=(int)strlen(text);
139 if (textLen==0)
140 return;
141 if (text[textLen-1]=='\n')
142 {
143 text[textLen-1]=0;
144 }
145 if (textLen < REMOTE_MAX_TEXT_INPUT-4)
146 strcat(text, "\r\n");
147 else
148 {
149 text[textLen-3]='\r';
150 text[textLen-2]='\n';
151 text[textLen-1]=0;
152 }
153
154 // For each user that subscribes to this channel, send to them.
155 unsigned i;
156 for (i=0; i < remoteUsers.Size(); i++)
157 {
158 if (remoteUsers[i].channels & (1 << channelIndex))
159 {
160 trans->Send(remoteUsers[i].systemAddress, text);
161 }
162 }
163 }
PrintChannels(SystemAddress systemAddress,TransportInterface * transport) const164 void LogCommandParser::PrintChannels(SystemAddress systemAddress, TransportInterface *transport) const
165 {
166 unsigned i;
167 bool anyChannels=false;
168 transport->Send(systemAddress, "CHANNELS:\r\n");
169 for (i=0; i < 32; i++)
170 {
171 if (channelNames[i])
172 {
173 transport->Send(systemAddress, "%i. %s\r\n", i+1,channelNames[i]);
174 anyChannels=true;
175 }
176 }
177 if (anyChannels==false)
178 transport->Send(systemAddress, "None.\r\n");
179 }
OnNewIncomingConnection(SystemAddress systemAddress,TransportInterface * transport)180 void LogCommandParser::OnNewIncomingConnection(SystemAddress systemAddress, TransportInterface *transport)
181 {
182 (void) systemAddress;
183 (void) transport;
184 }
OnConnectionLost(SystemAddress systemAddress,TransportInterface * transport)185 void LogCommandParser::OnConnectionLost(SystemAddress systemAddress, TransportInterface *transport)
186 {
187 (void) transport;
188 Unsubscribe(systemAddress, 0);
189 }
Unsubscribe(SystemAddress systemAddress,const char * channelName)190 unsigned LogCommandParser::Unsubscribe(SystemAddress systemAddress, const char *channelName)
191 {
192 unsigned i;
193 for (i=0; i < remoteUsers.Size(); i++)
194 {
195 if (remoteUsers[i].systemAddress==systemAddress)
196 {
197 if (channelName==0)
198 {
199 // Unsubscribe from all and delete this user.
200 remoteUsers[i]=remoteUsers[remoteUsers.Size()-1];
201 remoteUsers.RemoveFromEnd();
202 return 0;
203 }
204 else
205 {
206 unsigned channelIndex;
207 channelIndex = GetChannelIndexFromName(channelName);
208 if (channelIndex!=(unsigned)-1)
209 {
210 remoteUsers[i].channels&=0xFFFF ^ (1<<channelIndex); // Unset this bit
211 }
212 return channelIndex;
213 }
214 }
215 }
216 return (unsigned)-1;
217 }
Subscribe(SystemAddress systemAddress,const char * channelName)218 unsigned LogCommandParser::Subscribe(SystemAddress systemAddress, const char *channelName)
219 {
220 unsigned i;
221 unsigned channelIndex=(unsigned)-1;
222 if (channelName)
223 {
224 channelIndex = GetChannelIndexFromName(channelName);
225 if (channelIndex==(unsigned)-1)
226 return channelIndex;
227 }
228
229 for (i=0; i < remoteUsers.Size(); i++)
230 {
231 if (remoteUsers[i].systemAddress==systemAddress)
232 {
233 if (channelName)
234 remoteUsers[i].channels|=1<<channelIndex; // Set this bit for an existing user
235 else
236 remoteUsers[i].channels=0xFFFF;
237 return channelIndex;
238 }
239 }
240
241 // Make a new user
242 SystemAddressAndChannel newUser;
243 newUser.systemAddress = systemAddress;
244 if (channelName)
245 newUser.channels=1<<channelIndex;
246 else
247 newUser.channels=0xFFFF;
248 remoteUsers.Insert(newUser, __FILE__, __LINE__);
249 return channelIndex;
250 }
GetChannelIndexFromName(const char * channelName)251 unsigned LogCommandParser::GetChannelIndexFromName(const char *channelName)
252 {
253 unsigned i;
254 for (i=0; i < 32; i++)
255 {
256 if (channelNames[i]==0)
257 return (unsigned) -1;
258
259 if (_stricmp(channelNames[i], channelName)==0)
260 return i;
261 }
262 return (unsigned)-1;
263 }
264
OnTransportChange(TransportInterface * transport)265 void LogCommandParser::OnTransportChange(TransportInterface *transport)
266 {
267 // I don't want users to have to pass TransportInterface *transport to Log.
268 trans=transport;
269 }
270
271 #ifdef _MSC_VER
272 #pragma warning( pop )
273 #endif
274
275 #endif // _RAKNET_SUPPORT_*
276