summaryrefslogtreecommitdiff
path: root/client/service/service.gd
blob: f19364c75b057346c12b08a3ea9c4f35d41ae410 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# Hurry Curry! - a game about cooking
# Copyright 2024 metamuffin
# Copyright 2024 nokoe
# Copyright 2024 tpart
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
class_name Service
extends Node


func name():
	return "Unknown"
func arguments():
	return []
func exe_path():
	return "false"
func test_port():
	return 25565

var thread = null
var pid = null

var state = State.TESTING
enum State {
	TESTING,
	UNAVAILABLE,
	FAILED,
	STOPPED,
	STARTING,
	RUNNING,
}

var sem = Semaphore.new()
var thread_result = null;

func _ready():
	state = State.TESTING
	thread = Thread.new()
	thread.start(_test_server)

func test():
	pass

func start():
	if state != State.STOPPED and state != State.FAILED:
		push_error(name() + " can't be started")
		return
	state = State.STARTING
	thread = Thread.new()
	thread.start(_server_exec)

func stop():
	if state != State.RUNNING:
		push_error(name() + " can't be stopped")
		return
	OS.kill(pid)

func _test_server():
	var output = []
	print(name() + ": Binary path is " + exe_path())
	thread_result = OS.execute(exe_path(), ["-v"], output, true, false)
	print(output)
	sem.post()

func _server_exec():
	var args = arguments()
	thread_result = OS.create_process(exe_path(), args, false)
	if thread_result >= 0:
		var ok = false
		while not ok:
			var conn = StreamPeerTCP.new()
			if conn.connect_to_host("127.0.0.1", test_port()) == OK:
				while conn.poll() == OK:
					if conn.get_status() == StreamPeerTCP.STATUS_ERROR: break
					elif conn.get_status() == StreamPeerTCP.STATUS_CONNECTED: ok = true; break
					OS.delay_msec(10)
			OS.delay_msec(500 if not ok else 50)
			if !OS.is_process_running(thread_result):
				thread_result = -1
				break
	sem.post()

func _process(_delta):
	match state:
		State.TESTING:
			if sem.try_wait():
				print(name() + ": Test result=", thread_result)
				if thread_result == 0: state = State.STOPPED
				else: state = State.UNAVAILABLE
				thread.wait_to_finish()
				thread = null
		State.STARTING:
			if sem.try_wait():
				if thread_result >= 0:
					state = State.RUNNING
					pid = thread_result
					print(name() + ": Started pid=", thread_result)
				else:
					state = State.FAILED
					print(name() + ": Failed")
				thread.wait_to_finish()
				thread = null
		State.RUNNING:
			if not OS.is_process_running(pid):
				print(name() + ": Stopped")
				state = State.STOPPED
				pid = null

func _exit_tree():
	if pid != null: OS.kill(pid)
	if thread != null: thread.wait_to_finish()