Crossfire JXClient, Trunk
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-2017,2019-2023 Andreas Kirschbaum
20  * Copyright (C) 2010-2012,2014-2018,2020-2023 Nicolas Weeger
21  */
22 
23 package com.realtime.crossfire.jxclient.metaserver;
24 
26 import java.io.IOException;
27 import java.util.regex.Pattern;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30 
35 public class MetaserverEntryParser {
36 
40  @NotNull
41  private static final String UNKNOWN_VERSION = "?";
42 
46  @NotNull
47  private static final String DEFAULT_BASE = "not specified";
48 
52  @NotNull
53  private static final Pattern FIELD_SEPARATOR_PATTERN = Pattern.compile("\\|");
54 
58  private boolean inSection;
59 
63  private int updateSeconds;
64 
68  @Nullable
69  private String hostname;
70 
74  private int port;
75 
79  private int players;
80 
84  @NotNull
85  private String version = UNKNOWN_VERSION;
86 
91  @NotNull
92  private String comment = "";
93 
97  private long bytesIn;
98 
102  private long bytesOut;
103 
107  private int uptimeSeconds;
108 
112  @NotNull
113  private String archBase = DEFAULT_BASE;
114 
118  @NotNull
119  private String mapBase = DEFAULT_BASE;
120 
124  @NotNull
125  private String codeBase = DEFAULT_BASE;
126 
131  clear();
132  }
133 
139  @Nullable
140  public static MetaserverEntry parseEntry(@NotNull final CharSequence entry) {
141  final String[] entries = FIELD_SEPARATOR_PATTERN.split(entry, -1);
142  if (entries.length != 11) {
143  return null;
144  }
145 
146  final int updateSeconds;
147  final String hostname;
148  final int players;
149  final String version;
150  final String comment;
151  final long bytesIn;
152  final long bytesOut;
153  final int uptimeSeconds;
154  final String archBase;
155  final String mapBase;
156  final String codeBase;
157  try {
158  updateSeconds = Integer.parseInt(entries[0]);
159  hostname = entries[1];
160  players = Integer.parseInt(entries[2]);
161  version = entries[3];
162  comment = entries[4];
163  bytesIn = Long.parseLong(entries[5]);
164  bytesOut = Long.parseLong(entries[6]);
165  uptimeSeconds = Integer.parseInt(entries[7]);
166  archBase = entries[8];
167  codeBase = entries[9];
168  mapBase = entries[10];
169  } catch (final NumberFormatException ignored) {
170  return null;
171  }
172 
174  }
175 
182  @Nullable
183  public MetaserverEntry parseLine(@NotNull final String line) throws IOException {
184  if (inSection) {
185  if (line.equals("END_SERVER_DATA")) {
186  @Nullable final MetaserverEntry metaserverEntry;
187  if (hostname == null) {
188  System.err.println("Warning: metaserver response missing hostname field, skipping");
189  metaserverEntry = null;
190  } else {
192  }
193  clear();
194  inSection = false;
195  return metaserverEntry;
196  }
197  final String[] tmp = line.split("=", 2);
198  if (tmp.length == 2) {
199  final String key = tmp[0];
200  final String value = tmp[1];
201  switch (key) {
202  case "hostname":
203  hostname = value;
204  break;
205 
206  case "port":
207  port = NumberParser.parseInt(value, 13327);
208  break;
209 
210  case "html_comment":
211  comment = value;
212  break;
213 
214  case "text_comment":
215  if (comment.isEmpty()) {
216  comment = value;
217  }
218  break;
219 
220  case "archbase":
221  archBase = value;
222  break;
223 
224  case "mapbase":
225  mapBase = value;
226  break;
227 
228  case "codebase":
229  codeBase = value;
230  break;
231 
232  case "num_players":
233  players = NumberParser.parseInt(value, 0);
234  break;
235 
236  case "in_bytes":
237  bytesIn = NumberParser.parseLong(value, 0);
238  break;
239 
240  case "out_bytes":
241  bytesOut = NumberParser.parseLong(value, 0);
242  break;
243 
244  case "uptime":
245  uptimeSeconds = NumberParser.parseInt(value, 0);
246  break;
247 
248  case "version":
249  version = value;
250  break;
251 
252  case "sc_version":
253  break;
254 
255  case "cs_version":
256  break;
257 
258  case "last_update":
259  final long now = (System.currentTimeMillis()+500)/1000;
260  final long uptime = NumberParser.parseLong(value, now);
261  updateSeconds = Math.max((int)((uptime-now)/1000), 0);
262  break;
263 
264  case "flags":
265  break;
266 
267  default:
268  System.err.println("Ignoring unknown key: "+key);
269  break;
270  }
271  } else {
272  throw new IOException("syntax error: "+line);
273  }
274  } else {
275  if (line.equals("START_SERVER_DATA")) {
276  inSection = true;
277  } else {
278  throw new IOException("syntax error: "+line);
279  }
280  }
281 
282  return null;
283  }
284 
289  private void clear() {
290  updateSeconds = 0;
291  hostname = null;
292  port = 13327;
293  players = 0;
295  comment = "";
296  bytesIn = 0;
297  bytesOut = 0;
298  uptimeSeconds = 0;
302  }
303 
310  @NotNull
311  public static String format(@NotNull final MetaserverEntry entry) {
312  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());
313  }
314 
320  @NotNull
321  private static String replace(@NotNull final String str) {
322  return str.replaceAll("[|\r\n]", " ");
323  }
324 
325 }
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.UNKNOWN_VERSION
static final String UNKNOWN_VERSION
Definition: MetaserverEntryParser.java:41
com.realtime.crossfire.jxclient
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.DEFAULT_BASE
static final String DEFAULT_BASE
Definition: MetaserverEntryParser.java:47
com.realtime.crossfire.jxclient.util.NumberParser.parseLong
static long parseLong(@NotNull final String string, final long defaultValue)
Definition: NumberParser.java:80
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.parseEntry
static MetaserverEntry parseEntry(@NotNull final CharSequence entry)
Definition: MetaserverEntryParser.java:140
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.players
int players
Definition: MetaserverEntryParser.java:79
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.format
static String format(@NotNull final MetaserverEntry entry)
Definition: MetaserverEntryParser.java:311
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.MetaserverEntryParser
MetaserverEntryParser()
Definition: MetaserverEntryParser.java:130
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.replace
static String replace(@NotNull final String str)
Definition: MetaserverEntryParser.java:321
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.inSection
boolean inSection
Definition: MetaserverEntryParser.java:58
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.uptimeSeconds
int uptimeSeconds
Definition: MetaserverEntryParser.java:107
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.clear
void clear()
Definition: MetaserverEntryParser.java:289
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.version
String version
Definition: MetaserverEntryParser.java:85
com.realtime.crossfire.jxclient.util.NumberParser.parseInt
static int parseInt(@NotNull final String string, final int defaultValue)
Definition: NumberParser.java:46
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.codeBase
String codeBase
Definition: MetaserverEntryParser.java:125
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.archBase
String archBase
Definition: MetaserverEntryParser.java:113
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.mapBase
String mapBase
Definition: MetaserverEntryParser.java:119
com.realtime.crossfire.jxclient.util
Definition: Codec.java:23
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser
Definition: MetaserverEntryParser.java:35
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.comment
String comment
Definition: MetaserverEntryParser.java:92
com.realtime.crossfire
com.realtime
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.port
int port
Definition: MetaserverEntryParser.java:74
com
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.hostname
String hostname
Definition: MetaserverEntryParser.java:69
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.FIELD_SEPARATOR_PATTERN
static final Pattern FIELD_SEPARATOR_PATTERN
Definition: MetaserverEntryParser.java:53
com.realtime.crossfire.jxclient.util.NumberParser
Definition: NumberParser.java:32
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.parseLine
MetaserverEntry parseLine(@NotNull final String line)
Definition: MetaserverEntryParser.java:183
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.bytesOut
long bytesOut
Definition: MetaserverEntryParser.java:102
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.updateSeconds
int updateSeconds
Definition: MetaserverEntryParser.java:63
com.realtime.crossfire.jxclient.metaserver.MetaserverEntry
Definition: MetaserverEntry.java:33
com.realtime.crossfire.jxclient.metaserver.MetaserverEntryParser.bytesIn
long bytesIn
Definition: MetaserverEntryParser.java:97