Bump copyright years
[cacert-votebot.git] / src / main / java / org / cacert / votebot / vote / CAcertVoteBot.java
1 /*
2 * Copyright (c) 2015 Felix Doerre
3 * Copyright (c) 2015 Benny Baumann
4 * Copyright (c) 2016 Jan Dittberner
5 *
6 * This file is part of CAcert votebot.
7 *
8 * CAcert votebot is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation, either version 3 of the License, or (at your option)
11 * any later version.
12 *
13 * CAcert votebot is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * CAcert votebot. If not, see <http://www.gnu.org/licenses/>.
20 */
21 package org.cacert.votebot.vote;
22
23 import org.apache.commons.cli.ParseException;
24 import org.cacert.votebot.shared.CAcertVoteMechanics;
25 import org.cacert.votebot.shared.CAcertVoteMechanics.State;
26 import org.cacert.votebot.shared.IRCBot;
27 import org.cacert.votebot.shared.IRCClient;
28 import org.cacert.votebot.shared.exceptions.IRCClientException;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.beans.factory.annotation.Autowired;
32 import org.springframework.beans.factory.annotation.Value;
33 import org.springframework.boot.CommandLineRunner;
34 import org.springframework.boot.SpringApplication;
35 import org.springframework.boot.autoconfigure.SpringBootApplication;
36 import org.springframework.stereotype.Component;
37
38 import java.io.IOException;
39
40
41 /**
42 * Vote bot.
43 *
44 * @author Felix Doerre
45 * @author Jan Dittberner
46 */
47 @SpringBootApplication(scanBasePackageClasses = {IRCClient.class, CAcertVoteBot.class})
48 @Component
49 public class CAcertVoteBot extends IRCBot implements Runnable, CommandLineRunner {
50 private static final Logger LOGGER = LoggerFactory.getLogger(CAcertVoteBot.class);
51 private static final int MILLIS_ONE_SECOND = 1000;
52
53 /**
54 * Meeting channel where votes and results are published.
55 */
56 @Value("${voteBot.meetingChn}")
57 private String meetingChannel;
58
59 /**
60 * Channel name where voting is performed.
61 */
62 @Value("${voteBot.voteChn}")
63 private String voteChannel;
64
65 /**
66 * Seconds to warn before a vote ends.
67 */
68 @Value("${voteBot.warnSecs}")
69 private long warn;
70
71 /**
72 * Seconds before a vote times out.
73 */
74 @Value("${voteBot.timeoutSecs}")
75 private long timeout;
76
77 @Autowired
78 private CAcertVoteMechanics voteMechanics;
79
80 @Autowired
81 private IRCClient ircClient;
82
83 /**
84 * {@inheritDoc}
85 *
86 * @param args command line arguments
87 */
88 @Override
89 public final void run(final String... args) {
90 try {
91 getIrcClient().initializeFromArgs(args).assignBot(this);
92
93 getIrcClient().join(meetingChannel);
94 getIrcClient().join(voteChannel);
95
96 new Thread(this).start();
97 } catch (IOException | InterruptedException | ParseException | IRCClientException e) {
98 LOGGER.error(String.format("error running votebot %s", e.getMessage()));
99 }
100 }
101
102 @Override
103 protected final IRCClient getIrcClient() {
104 return ircClient;
105 }
106
107 @Override
108 public final synchronized void publicMessage(final String from, final String channel, final String message) throws
109 IRCClientException {
110 if (channel.equals(voteChannel)) {
111 sendPublicMessage(voteChannel, voteMechanics.evaluateVote(from, message));
112 }
113 }
114
115 @Override
116 public final synchronized void privateMessage(final String from, final String message) throws IRCClientException {
117 if (message.startsWith("vote ")) {
118 final String response = voteMechanics.callVote(message.substring(5));
119 sendPrivateMessage(from, response);
120
121 if (response.startsWith("Sorry,")) {
122 return;
123 }
124
125 announce("New Vote: " + from + " has started a vote on \"" + voteMechanics.getTopic() + "\"");
126 sendPublicMessage(meetingChannel, "Please cast your vote in #vote");
127 sendPublicMessage(voteChannel, "Please cast your vote in the next " + timeout + " seconds.");
128 }
129 }
130
131 private synchronized void announce(final String msg) throws IRCClientException {
132 sendPublicMessage(meetingChannel, msg);
133 sendPublicMessage(voteChannel, msg);
134 }
135
136 @Override
137 public final void run() {
138 try {
139 //noinspection InfiniteLoopStatement
140 while (true) {
141 while (voteMechanics.getState() == State.IDLE) {
142 Thread.sleep(MILLIS_ONE_SECOND);
143 }
144
145 Thread.sleep(warn * MILLIS_ONE_SECOND);
146 announce("Voting on " + voteMechanics.getTopic() + " will end in " + (timeout - warn) + " seconds.");
147 Thread.sleep((timeout - warn) * MILLIS_ONE_SECOND);
148 announce("Voting on " + voteMechanics.getTopic() + " has closed.");
149 final String[] res = voteMechanics.closeVote();
150 announce("Results: for " + voteMechanics.getTopic() + ":");
151
152 for (final String re : res) {
153 announce(re);
154 }
155 }
156 } catch (final InterruptedException | IRCClientException e) {
157 LOGGER.error(e.getMessage(), e);
158 }
159 }
160
161 @Override
162 public synchronized void join(final String referent, final String chn) {
163
164 }
165
166 @Override
167 public synchronized void part(final String referent, final String channel) {
168
169 }
170
171 /**
172 * Entry point for the vote bot.
173 *
174 * @param args command line arguments
175 */
176 public static void main(final String... args) {
177 SpringApplication.run(CAcertVoteBot.class, args);
178 }
179 }