Crossfire JXClient, Trunk  R20561
MetaserverEntryParser.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.metaserver;
23 
25 import java.io.IOException;
26 import java.util.regex.Pattern;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29 
34 public class MetaserverEntryParser {
35 
39  @NotNull
40  private static final String UNKNOWN_VERSION = "?";
41 
45  @NotNull
46  private static final String DEFAULT_BASE = "not specified";
47 
51  @NotNull
52  private static final Pattern FIELD_SEPARATOR_PATTERN = Pattern.compile("\\|");
53 
57  private boolean inSection;
58 
62  private int updateSeconds;
63 
67  @Nullable
68  private String hostname;
69 
73  private int players;
74 
78  @NotNull
79  private String version = UNKNOWN_VERSION;
80 
85  @NotNull
86  private String comment = "";
87 
91  private long bytesIn;
92 
96  private long bytesOut;
97 
101  private int uptimeSeconds;
102 
106  @NotNull
107  private String archBase = DEFAULT_BASE;
108 
112  @NotNull
113  private String mapBase = DEFAULT_BASE;
114 
118  @NotNull
119  private String codeBase = DEFAULT_BASE;
120 
125  clear();
126  }
127 
133  @Nullable
134  public static MetaserverEntry parseEntry(@NotNull final CharSequence entry) {
135  final String[] entries = FIELD_SEPARATOR_PATTERN.split(entry, -1);
136  if (entries.length != 11) {
137  return null;
138  }
139 
140  final int updateSeconds;
141  final String hostname;
142  final int players;
143  final String version;
144  final String comment;
145  final long bytesIn;
146  final long bytesOut;
147  final int uptimeSeconds;
148  final String archBase;
149  final String mapBase;
150  final String codeBase;
151  try {
152  updateSeconds = Integer.parseInt(entries[0]);
153  hostname = entries[1];
154  players = Integer.parseInt(entries[2]);
155  version = entries[3];
156  comment = entries[4];
157  bytesIn = Long.parseLong(entries[5]);
158  bytesOut = Long.parseLong(entries[6]);
159  uptimeSeconds = Integer.parseInt(entries[7]);
160  archBase = entries[8];
161  codeBase = entries[9];
162  mapBase = entries[10];
163  } catch (final NumberFormatException ignored) {
164  return null;
165  }
166 
167  return new MetaserverEntry(updateSeconds, hostname, players, version, comment, bytesIn, bytesOut, uptimeSeconds, archBase, codeBase, mapBase);
168  }
169 
176  @Nullable
177  @SuppressWarnings("IfStatementWithIdenticalBranches")
178  public MetaserverEntry parseLine(@NotNull final String line) throws IOException {
179  if (inSection) {
180  if (line.equals("END_SERVER_DATA")) {
181  @Nullable final MetaserverEntry metaserverEntry;
182  if (hostname == null) {
183  System.err.println("Warning: metaserver response missing hostname field, skipping");
184  metaserverEntry = null;
185  } else {
186  metaserverEntry = new MetaserverEntry(updateSeconds, hostname, players, version, comment, bytesIn, bytesOut, uptimeSeconds, archBase, mapBase, codeBase);
187  }
188  clear();
189  inSection = false;
190  return metaserverEntry;
191  }
192  final String[] tmp = line.split("=", 2);
193  if (tmp.length == 2) {
194  final String key = tmp[0];
195  final String value = tmp[1];
196  switch (key) {
197  case "hostname":
198  hostname = value;
199  break;
200 
201  case "port":
202  break;
203 
204  case "html_comment":
205  comment = value;
206  break;
207 
208  case "text_comment":
209  if (comment.isEmpty()) {
210  comment = value;
211  }
212  break;
213 
214  case "archbase":
215  archBase = value;
216  break;
217 
218  case "mapbase":
219  mapBase = value;
220  break;
221 
222  case "codebase":
223  codeBase = value;
224  break;
225 
226  case "num_players":
227  players = NumberParser.parseInt(value, 0);
228  break;
229 
230  case "in_bytes":
231  bytesIn = NumberParser.parseLong(value, 0);
232  break;
233 
234  case "out_bytes":
235  bytesOut = NumberParser.parseLong(value, 0);
236  break;
237 
238  case "uptime":
239  uptimeSeconds = NumberParser.parseInt(value, 0);
240  break;
241 
242  case "version":
243  version = value;
244  break;
245 
246  case "sc_version":
247  break;
248 
249  case "cs_version":
250  break;
251 
252  case "last_update":
253  final long now = (System.currentTimeMillis()+500)/1000;
254  final long uptime = NumberParser.parseLong(value, now);
255  updateSeconds = Math.max((int)((uptime-now)/1000), 0);
256  break;
257 
258  case "flags":
259  break;
260 
261  default:
262  System.err.println("Ignoring unknown key: "+key);
263  break;
264  }
265  } else {
266  throw new IOException("syntax error: "+line);
267  }
268  } else {
269  if (line.equals("START_SERVER_DATA")) {
270  inSection = true;
271  } else {
272  throw new IOException("syntax error: "+line);
273  }
274  }
275 
276  return null;
277  }
278 
283  private void clear() {
284  updateSeconds = 0;
285  hostname = null;
286  players = 0;
288  comment = "";
289  bytesIn = 0;
290  bytesOut = 0;
291  uptimeSeconds = 0;
295  }
296 
303  @NotNull
304  public static String format(@NotNull final MetaserverEntry entry) {
305  return entry.getUpdateSeconds()+"|"+replace(entry.getHostname())+"|"+entry.getPlayers()+"|"+replace(entry.getVersion())+"|"+replace(entry.getComment())+"|"+entry.getBytesIn()+"|"+entry.getBytesOut()+"|"+entry.getUptimeSeconds()+"|"+replace(entry.getArchBase())+"|"+replace(entry.getCodeBase())+"|"+replace(entry.getMapBase());
306  }
307 
313  @NotNull
314  private static String replace(@NotNull final String str) {
315  return str.replaceAll("[\\|\r\n]", " ");
316  }
317 
318 }
int updateSeconds
The "update seconds" value for the current server entry.
String codeBase
The "code base" value for the current server entry.
int players
The "players" value for the current server entry.
long bytesIn
The "bytes in" value for the current server entry.
boolean inSection
Whether response parsing is withing a server entry.
String comment
The "comment" value for the current server entry.
static long parseLong(@NotNull final String string, final long defaultValue)
Converts a string into a long value.
static String replace(@NotNull final String str)
Replaces characters with may cause parsing issues.
Represents a response line from the metaserver.
static final String DEFAULT_BASE
The default for arch base, map base, and code base if none specified.
static final Pattern FIELD_SEPARATOR_PATTERN
The pattern to split a metaserver response line into fields.
static String format(@NotNull final MetaserverEntry entry)
Formats a metaserver entry that returns the metaserver entry when parse with parseEntry(CharSequence)...
static int parseInt(@NotNull final String string, final int defaultValue)
Converts a string into an int value.
int uptimeSeconds
The "uptime seconds" value for the current server entry.
String hostname
The "hostname" value for the current server entry.
MetaserverEntry parseLine(@NotNull final String line)
Parses a metaserver response line.
static final String UNKNOWN_VERSION
The default server version if none specified.
Utility class for parsing strings into numbers.
String archBase
The "archetype base" value for the current server entry.
Parser for response lines of metaserver response lines.
static MetaserverEntry parseEntry(@NotNull final CharSequence entry)
Parses a metaserver response line.
String mapBase
The "map base" value for the current server entry.
String version
The "server version" value for the current server entry.
long bytesOut
The "bytes out" value for the current server entry.
void clear()
Resets values for the current server entry.