diff --git a/_configuration_8cs_source.html b/_configuration_8cs_source.html index 5098cd396c1..dc8bb9c3526 100644 --- a/_configuration_8cs_source.html +++ b/_configuration_8cs_source.html @@ -200,578 +200,580 @@
202 {
203 using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken))
204 {
-
205 await EnsureDirectories(cancellationToken);
+
205 var ensureDirectoriesTask = EnsureDirectories(cancellationToken);
206
207 // just assume no other fs race conditions here
208 var dmeExistsTask = ioManager.FileExists(ioManager.ConcatPath(CodeModificationsSubdirectory, dmeFile), cancellationToken);
209 var headFileExistsTask = ioManager.FileExists(ioManager.ConcatPath(CodeModificationsSubdirectory, CodeModificationsHeadFile), cancellationToken);
210 var tailFileExistsTask = ioManager.FileExists(ioManager.ConcatPath(CodeModificationsSubdirectory, CodeModificationsTailFile), cancellationToken);
-
211 var copyTask = ioManager.CopyDirectory(
-
212 null,
-
213 null,
-
214 CodeModificationsSubdirectory,
-
215 destination,
-
216 generalConfiguration.GetCopyDirectoryTaskThrottle(),
-
217 cancellationToken);
-
218
-
219 await Task.WhenAll(dmeExistsTask, headFileExistsTask, tailFileExistsTask, copyTask);
+
211
+
212 await ensureDirectoriesTask;
+
213 var copyTask = ioManager.CopyDirectory(
+
214 null,
+
215 null,
+
216 CodeModificationsSubdirectory,
+
217 destination,
+
218 generalConfiguration.GetCopyDirectoryTaskThrottle(),
+
219 cancellationToken);
220
-
221 if (!dmeExistsTask.Result && !headFileExistsTask.Result && !tailFileExistsTask.Result)
-
222 return null;
-
223
-
224 if (dmeExistsTask.Result)
-
225 return new ServerSideModifications(null, null, true);
-
226
-
227 if (!headFileExistsTask.Result && !tailFileExistsTask.Result)
-
228 return null;
-
229
-
230 static string IncludeLine(string filePath) => String.Format(CultureInfo.InvariantCulture, "#include \"{0}\"", filePath);
+
221 await Task.WhenAll(dmeExistsTask, headFileExistsTask, tailFileExistsTask, copyTask);
+
222
+
223 if (!dmeExistsTask.Result && !headFileExistsTask.Result && !tailFileExistsTask.Result)
+
224 return null;
+
225
+
226 if (dmeExistsTask.Result)
+
227 return new ServerSideModifications(null, null, true);
+
228
+
229 if (!headFileExistsTask.Result && !tailFileExistsTask.Result)
+
230 return null;
231
-
232 return new ServerSideModifications(headFileExistsTask.Result ? IncludeLine(CodeModificationsHeadFile) : null, tailFileExistsTask.Result ? IncludeLine(CodeModificationsTailFile) : null, false);
-
233 }
-
234 }
-
235
-
237 public async Task<IReadOnlyList<ConfigurationFileResponse>> ListDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
-
238 {
-
239 await EnsureDirectories(cancellationToken);
-
240 var path = ValidateConfigRelativePath(configurationRelativePath);
-
241
-
242 configurationRelativePath ??= "/";
+
232 static string IncludeLine(string filePath) => String.Format(CultureInfo.InvariantCulture, "#include \"{0}\"", filePath);
+
233
+
234 return new ServerSideModifications(headFileExistsTask.Result ? IncludeLine(CodeModificationsHeadFile) : null, tailFileExistsTask.Result ? IncludeLine(CodeModificationsTailFile) : null, false);
+
235 }
+
236 }
+
237
+
239 public async Task<IReadOnlyList<ConfigurationFileResponse>> ListDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
+
240 {
+
241 await EnsureDirectories(cancellationToken);
+
242 var path = ValidateConfigRelativePath(configurationRelativePath);
243
-
244 var result = new List<ConfigurationFileResponse>();
+
244 configurationRelativePath ??= "/";
245
-
246 void ListImpl()
-
247 {
-
248 var enumerator = synchronousIOManager.GetDirectories(path, cancellationToken);
-
249 result.AddRange(enumerator.Select(x => new ConfigurationFileResponse
-
250 {
-
251 IsDirectory = true,
-
252 Path = ioManager.ConcatPath(configurationRelativePath, x),
-
253 }).OrderBy(file => file.Path));
-
254
-
255 enumerator = synchronousIOManager.GetFiles(path, cancellationToken);
-
256 result.AddRange(enumerator.Select(x => new ConfigurationFileResponse
-
257 {
-
258 IsDirectory = false,
-
259 Path = ioManager.ConcatPath(configurationRelativePath, x),
-
260 }).OrderBy(file => file.Path));
-
261 }
-
262
-
263 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
-
264 {
-
265 if (!locked)
-
266 {
-
267 logger.LogDebug("Contention when attempting to enumerate directory!");
-
268 return null;
-
269 }
-
270
-
271 if (systemIdentity == null)
-
272 ListImpl();
-
273 else
-
274 await systemIdentity.RunImpersonated(ListImpl, cancellationToken);
-
275 }
-
276
-
277 return result;
-
278 }
-
279
-
281 public async Task<ConfigurationFileResponse> Read(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
-
282 {
-
283 await EnsureDirectories(cancellationToken);
-
284 var path = ValidateConfigRelativePath(configurationRelativePath);
-
285
-
286 ConfigurationFileResponse result = null;
+
246 var result = new List<ConfigurationFileResponse>();
+
247
+
248 void ListImpl()
+
249 {
+
250 var enumerator = synchronousIOManager.GetDirectories(path, cancellationToken);
+
251 result.AddRange(enumerator.Select(x => new ConfigurationFileResponse
+
252 {
+
253 IsDirectory = true,
+
254 Path = ioManager.ConcatPath(configurationRelativePath, x),
+
255 }).OrderBy(file => file.Path));
+
256
+
257 enumerator = synchronousIOManager.GetFiles(path, cancellationToken);
+
258 result.AddRange(enumerator.Select(x => new ConfigurationFileResponse
+
259 {
+
260 IsDirectory = false,
+
261 Path = ioManager.ConcatPath(configurationRelativePath, x),
+
262 }).OrderBy(file => file.Path));
+
263 }
+
264
+
265 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
+
266 {
+
267 if (!locked)
+
268 {
+
269 logger.LogDebug("Contention when attempting to enumerate directory!");
+
270 return null;
+
271 }
+
272
+
273 if (systemIdentity == null)
+
274 ListImpl();
+
275 else
+
276 await systemIdentity.RunImpersonated(ListImpl, cancellationToken);
+
277 }
+
278
+
279 return result;
+
280 }
+
281
+
283 public async Task<ConfigurationFileResponse> Read(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
+
284 {
+
285 await EnsureDirectories(cancellationToken);
+
286 var path = ValidateConfigRelativePath(configurationRelativePath);
287
-
288 void ReadImpl()
-
289 {
-
290 try
-
291 {
-
292 string GetFileSha()
-
293 {
-
294 var content = synchronousIOManager.ReadFile(path);
-
295 using var sha1 = SHA1.Create();
-
296 return String.Join(String.Empty, sha1.ComputeHash(content).Select(b => b.ToString("x2", CultureInfo.InvariantCulture)));
-
297 }
-
298
-
299 var originalSha = GetFileSha();
+
288 ConfigurationFileResponse result = null;
+
289
+
290 void ReadImpl()
+
291 {
+
292 try
+
293 {
+
294 string GetFileSha()
+
295 {
+
296 var content = synchronousIOManager.ReadFile(path);
+
297 using var sha1 = SHA1.Create();
+
298 return String.Join(String.Empty, sha1.ComputeHash(content).Select(b => b.ToString("x2", CultureInfo.InvariantCulture)));
+
299 }
300
-
301 var disposeToken = disposeCts.Token;
-
302 var fileTicket = fileTransferService.CreateDownload(
-
303 new FileDownloadProvider(
-
304 () =>
-
305 {
-
306 if (disposeToken.IsCancellationRequested)
-
307 return ErrorCode.InstanceOffline;
-
308
-
309 var newSha = GetFileSha();
-
310 if (newSha != originalSha)
-
311 return ErrorCode.ConfigurationFileUpdated;
-
312
-
313 return null;
-
314 },
-
315 async cancellationToken =>
-
316 {
-
317 FileStream result = null;
-
318 void GetFileStream()
-
319 {
-
320 result = ioManager.GetFileStream(path, false);
-
321 }
-
322
-
323 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
-
324 {
-
325 if (!locked)
-
326 return null;
-
327
-
328 if (systemIdentity == null)
-
329 await Task.Factory.StartNew(GetFileStream, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
-
330 else
-
331 await systemIdentity.RunImpersonated(GetFileStream, cancellationToken);
-
332 }
-
333
-
334 return result;
-
335 },
-
336 path,
-
337 false));
-
338
-
339 result = new ConfigurationFileResponse
-
340 {
-
341 FileTicket = fileTicket.FileTicket,
-
342 IsDirectory = false,
-
343 LastReadHash = originalSha,
-
344 AccessDenied = false,
-
345 Path = configurationRelativePath,
-
346 };
-
347 }
-
348 catch (UnauthorizedAccessException)
-
349 {
-
350 // this happens on windows, dunno about linux
-
351 bool isDirectory;
-
352 try
-
353 {
-
354 isDirectory = synchronousIOManager.IsDirectory(path);
-
355 }
-
356 catch (Exception ex)
-
357 {
-
358 logger.LogDebug(ex, "IsDirectory exception!");
-
359 isDirectory = false;
-
360 }
-
361
-
362 result = new ConfigurationFileResponse
-
363 {
-
364 Path = configurationRelativePath,
-
365 };
-
366 if (!isDirectory)
-
367 result.AccessDenied = true;
-
368
-
369 result.IsDirectory = isDirectory;
-
370 }
-
371 }
-
372
-
373 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
-
374 {
-
375 if (!locked)
-
376 {
-
377 logger.LogDebug("Contention when attempting to read file!");
-
378 return null;
-
379 }
-
380
-
381 if (systemIdentity == null)
-
382 await Task.Factory.StartNew(ReadImpl, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
-
383 else
-
384 await systemIdentity.RunImpersonated(ReadImpl, cancellationToken);
-
385 }
-
386
-
387 return result;
-
388 }
-
389
-
391 public async Task SymlinkStaticFilesTo(string destination, CancellationToken cancellationToken)
-
392 {
-
393 async Task<IReadOnlyList<string>> GetIgnoreFiles()
-
394 {
-
395 var ignoreFileBytes = await ioManager.ReadAllBytes(StaticIgnorePath(), cancellationToken);
-
396 var ignoreFileText = Encoding.UTF8.GetString(ignoreFileBytes);
-
397
-
398 var results = new List<string> { StaticIgnoreFile };
+
301 var originalSha = GetFileSha();
+
302
+
303 var disposeToken = disposeCts.Token;
+
304 var fileTicket = fileTransferService.CreateDownload(
+
305 new FileDownloadProvider(
+
306 () =>
+
307 {
+
308 if (disposeToken.IsCancellationRequested)
+
309 return ErrorCode.InstanceOffline;
+
310
+
311 var newSha = GetFileSha();
+
312 if (newSha != originalSha)
+
313 return ErrorCode.ConfigurationFileUpdated;
+
314
+
315 return null;
+
316 },
+
317 async cancellationToken =>
+
318 {
+
319 FileStream result = null;
+
320 void GetFileStream()
+
321 {
+
322 result = ioManager.GetFileStream(path, false);
+
323 }
+
324
+
325 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
+
326 {
+
327 if (!locked)
+
328 return null;
+
329
+
330 if (systemIdentity == null)
+
331 await Task.Factory.StartNew(GetFileStream, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
+
332 else
+
333 await systemIdentity.RunImpersonated(GetFileStream, cancellationToken);
+
334 }
+
335
+
336 return result;
+
337 },
+
338 path,
+
339 false));
+
340
+
341 result = new ConfigurationFileResponse
+
342 {
+
343 FileTicket = fileTicket.FileTicket,
+
344 IsDirectory = false,
+
345 LastReadHash = originalSha,
+
346 AccessDenied = false,
+
347 Path = configurationRelativePath,
+
348 };
+
349 }
+
350 catch (UnauthorizedAccessException)
+
351 {
+
352 // this happens on windows, dunno about linux
+
353 bool isDirectory;
+
354 try
+
355 {
+
356 isDirectory = synchronousIOManager.IsDirectory(path);
+
357 }
+
358 catch (Exception ex)
+
359 {
+
360 logger.LogDebug(ex, "IsDirectory exception!");
+
361 isDirectory = false;
+
362 }
+
363
+
364 result = new ConfigurationFileResponse
+
365 {
+
366 Path = configurationRelativePath,
+
367 };
+
368 if (!isDirectory)
+
369 result.AccessDenied = true;
+
370
+
371 result.IsDirectory = isDirectory;
+
372 }
+
373 }
+
374
+
375 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
+
376 {
+
377 if (!locked)
+
378 {
+
379 logger.LogDebug("Contention when attempting to read file!");
+
380 return null;
+
381 }
+
382
+
383 if (systemIdentity == null)
+
384 await Task.Factory.StartNew(ReadImpl, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
+
385 else
+
386 await systemIdentity.RunImpersonated(ReadImpl, cancellationToken);
+
387 }
+
388
+
389 return result;
+
390 }
+
391
+
393 public async Task SymlinkStaticFilesTo(string destination, CancellationToken cancellationToken)
+
394 {
+
395 async Task<IReadOnlyList<string>> GetIgnoreFiles()
+
396 {
+
397 var ignoreFileBytes = await ioManager.ReadAllBytes(StaticIgnorePath(), cancellationToken);
+
398 var ignoreFileText = Encoding.UTF8.GetString(ignoreFileBytes);
399
-
400 // we don't want to lose trailing whitespace on linux
-
401 using (var reader = new StringReader(ignoreFileText))
-
402 {
-
403 cancellationToken.ThrowIfCancellationRequested();
-
404 var line = await reader.ReadLineAsync();
-
405 if (!String.IsNullOrEmpty(line))
-
406 results.Add(line);
-
407 }
-
408
-
409 return results;
-
410 }
-
411
-
412 IReadOnlyList<string> ignoreFiles;
+
400 var results = new List<string> { StaticIgnoreFile };
+
401
+
402 // we don't want to lose trailing whitespace on linux
+
403 using (var reader = new StringReader(ignoreFileText))
+
404 {
+
405 cancellationToken.ThrowIfCancellationRequested();
+
406 var line = await reader.ReadLineAsync();
+
407 if (!String.IsNullOrEmpty(line))
+
408 results.Add(line);
+
409 }
+
410
+
411 return results;
+
412 }
413
-
414 async Task SymlinkBase(bool files)
-
415 {
-
416 Task<IReadOnlyList<string>> task;
-
417 if (files)
-
418 task = ioManager.GetFiles(GameStaticFilesSubdirectory, cancellationToken);
-
419 else
-
420 task = ioManager.GetDirectories(GameStaticFilesSubdirectory, cancellationToken);
-
421 var entries = await task;
-
422
-
423 await Task.WhenAll(entries.Select(async file =>
-
424 {
-
425 var fileName = ioManager.GetFileName(file);
-
426
-
427 // need to normalize
-
428 bool ignored;
-
429 if (platformIdentifier.IsWindows)
-
430 ignored = ignoreFiles.Any(y => fileName.ToUpperInvariant() == y.ToUpperInvariant());
-
431 else
-
432 ignored = ignoreFiles.Any(y => fileName == y);
-
433
-
434 if (ignored)
-
435 {
-
436 logger.LogTrace("Ignoring static file {fileName}...", fileName);
-
437 return;
-
438 }
-
439
-
440 var destPath = ioManager.ConcatPath(destination, fileName);
-
441 logger.LogTrace("Symlinking {filePath} to {destPath}...", file, destPath);
-
442 var fileExistsTask = ioManager.FileExists(destPath, cancellationToken);
-
443 if (await ioManager.DirectoryExists(destPath, cancellationToken))
-
444 await ioManager.DeleteDirectory(destPath, cancellationToken);
-
445 var fileExists = await fileExistsTask;
-
446 if (fileExists)
-
447 await ioManager.DeleteFile(destPath, cancellationToken);
-
448 await symlinkFactory.CreateSymbolicLink(ioManager.ResolvePath(file), ioManager.ResolvePath(destPath), cancellationToken);
-
449 }));
-
450 }
-
451
-
452 using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken))
-
453 {
-
454 await EnsureDirectories(cancellationToken);
-
455 ignoreFiles = await GetIgnoreFiles();
-
456 await Task.WhenAll(SymlinkBase(true), SymlinkBase(false));
-
457 }
-
458 }
-
459
-
461 public async Task<ConfigurationFileResponse> Write(string configurationRelativePath, ISystemIdentity systemIdentity, string previousHash, CancellationToken cancellationToken)
-
462 {
-
463 await EnsureDirectories(cancellationToken);
-
464 var path = ValidateConfigRelativePath(configurationRelativePath);
-
465
-
466 ConfigurationFileResponse result = null;
+
414 IReadOnlyList<string> ignoreFiles;
+
415
+
416 async Task SymlinkBase(bool files)
+
417 {
+
418 Task<IReadOnlyList<string>> task;
+
419 if (files)
+
420 task = ioManager.GetFiles(GameStaticFilesSubdirectory, cancellationToken);
+
421 else
+
422 task = ioManager.GetDirectories(GameStaticFilesSubdirectory, cancellationToken);
+
423 var entries = await task;
+
424
+
425 await Task.WhenAll(entries.Select(async file =>
+
426 {
+
427 var fileName = ioManager.GetFileName(file);
+
428
+
429 // need to normalize
+
430 bool ignored;
+
431 if (platformIdentifier.IsWindows)
+
432 ignored = ignoreFiles.Any(y => fileName.ToUpperInvariant() == y.ToUpperInvariant());
+
433 else
+
434 ignored = ignoreFiles.Any(y => fileName == y);
+
435
+
436 if (ignored)
+
437 {
+
438 logger.LogTrace("Ignoring static file {fileName}...", fileName);
+
439 return;
+
440 }
+
441
+
442 var destPath = ioManager.ConcatPath(destination, fileName);
+
443 logger.LogTrace("Symlinking {filePath} to {destPath}...", file, destPath);
+
444 var fileExistsTask = ioManager.FileExists(destPath, cancellationToken);
+
445 if (await ioManager.DirectoryExists(destPath, cancellationToken))
+
446 await ioManager.DeleteDirectory(destPath, cancellationToken);
+
447 var fileExists = await fileExistsTask;
+
448 if (fileExists)
+
449 await ioManager.DeleteFile(destPath, cancellationToken);
+
450 await symlinkFactory.CreateSymbolicLink(ioManager.ResolvePath(file), ioManager.ResolvePath(destPath), cancellationToken);
+
451 }));
+
452 }
+
453
+
454 using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken))
+
455 {
+
456 await EnsureDirectories(cancellationToken);
+
457 ignoreFiles = await GetIgnoreFiles();
+
458 await Task.WhenAll(SymlinkBase(true), SymlinkBase(false));
+
459 }
+
460 }
+
461
+
463 public async Task<ConfigurationFileResponse> Write(string configurationRelativePath, ISystemIdentity systemIdentity, string previousHash, CancellationToken cancellationToken)
+
464 {
+
465 await EnsureDirectories(cancellationToken);
+
466 var path = ValidateConfigRelativePath(configurationRelativePath);
467
-
468 void WriteImpl()
-
469 {
-
470 try
-
471 {
-
472 var fileTicket = fileTransferService.CreateUpload(FileUploadStreamKind.ForSynchronousIO);
-
473 var uploadCancellationToken = disposeCts.Token;
-
474 async Task UploadHandler()
-
475 {
-
476 await using (fileTicket)
-
477 {
-
478 var fileHash = previousHash;
-
479 var uploadStream = await fileTicket.GetResult(uploadCancellationToken);
-
480 if (uploadStream == null)
-
481 return; // expired
-
482
-
483 bool success = false;
-
484 void WriteCallback()
-
485 {
-
486 success = synchronousIOManager.WriteFileChecked(path, uploadStream, ref fileHash, cancellationToken);
-
487 }
-
488
-
489 if (fileTicket == null)
-
490 {
-
491 logger.LogDebug("File upload ticket for {path} expired!", path);
-
492 return;
-
493 }
-
494
-
495 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
-
496 {
-
497 if (!locked)
-
498 {
-
499 fileTicket.SetError(ErrorCode.ConfigurationContendedAccess, null);
-
500 return;
-
501 }
-
502
-
503 if (systemIdentity == null)
-
504 await Task.Factory.StartNew(WriteCallback, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
-
505 else
-
506 await systemIdentity.RunImpersonated(WriteCallback, cancellationToken);
-
507 }
-
508
-
509 if (!success)
-
510 fileTicket.SetError(ErrorCode.ConfigurationFileUpdated, fileHash);
-
511 else if (uploadStream.Length > 0)
-
512 postWriteHandler.HandleWrite(path);
-
513 }
-
514 }
-
515
-
516 result = new ConfigurationFileResponse
-
517 {
-
518 FileTicket = fileTicket.Ticket.FileTicket,
-
519 LastReadHash = previousHash,
-
520 IsDirectory = false,
-
521 AccessDenied = false,
-
522 Path = configurationRelativePath,
-
523 };
-
524
-
525 lock (disposeCts)
-
526 uploadTasks = Task.WhenAll(uploadTasks, UploadHandler());
-
527 }
-
528 catch (UnauthorizedAccessException)
-
529 {
-
530 // this happens on windows, dunno about linux
-
531 bool isDirectory;
-
532 try
-
533 {
-
534 isDirectory = synchronousIOManager.IsDirectory(path);
-
535 }
-
536 catch (Exception ex)
-
537 {
-
538 logger.LogDebug(ex, "IsDirectory exception!");
-
539 isDirectory = false;
-
540 }
-
541
-
542 result = new ConfigurationFileResponse
-
543 {
-
544 Path = configurationRelativePath,
-
545 };
-
546 if (!isDirectory)
-
547 result.AccessDenied = true;
-
548
-
549 result.IsDirectory = isDirectory;
-
550 }
-
551 }
-
552
-
553 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
-
554 {
-
555 if (!locked)
-
556 {
-
557 logger.LogDebug("Contention when attempting to write file!");
-
558 return null;
-
559 }
-
560
-
561 if (systemIdentity == null)
-
562 await Task.Factory.StartNew(WriteImpl, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
-
563 else
-
564 await systemIdentity.RunImpersonated(WriteImpl, cancellationToken);
-
565 }
-
566
-
567 return result;
-
568 }
-
569
-
571 public async Task<bool?> CreateDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
-
572 {
-
573 await EnsureDirectories(cancellationToken);
-
574 var path = ValidateConfigRelativePath(configurationRelativePath);
-
575
-
576 bool? result = null;
-
577 void DoCreate() => result = synchronousIOManager.CreateDirectory(path, cancellationToken);
-
578
-
579 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
-
580 {
-
581 if (!locked)
-
582 {
-
583 logger.LogDebug("Contention when attempting to create directory!");
-
584 return null;
-
585 }
-
586
-
587 if (systemIdentity == null)
-
588 await Task.Factory.StartNew(DoCreate, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
-
589 else
-
590 await systemIdentity.RunImpersonated(DoCreate, cancellationToken);
-
591 }
-
592
-
593 return result.Value;
-
594 }
-
595
-
597 public Task StartAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);
-
598
-
600 public Task StopAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);
-
601
-
603 public async Task HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
-
604 {
-
605 ArgumentNullException.ThrowIfNull(parameters);
-
606
-
607 await EnsureDirectories(cancellationToken);
+
468 ConfigurationFileResponse result = null;
+
469
+
470 void WriteImpl()
+
471 {
+
472 try
+
473 {
+
474 var fileTicket = fileTransferService.CreateUpload(FileUploadStreamKind.ForSynchronousIO);
+
475 var uploadCancellationToken = disposeCts.Token;
+
476 async Task UploadHandler()
+
477 {
+
478 await using (fileTicket)
+
479 {
+
480 var fileHash = previousHash;
+
481 var uploadStream = await fileTicket.GetResult(uploadCancellationToken);
+
482 if (uploadStream == null)
+
483 return; // expired
+
484
+
485 bool success = false;
+
486 void WriteCallback()
+
487 {
+
488 success = synchronousIOManager.WriteFileChecked(path, uploadStream, ref fileHash, cancellationToken);
+
489 }
+
490
+
491 if (fileTicket == null)
+
492 {
+
493 logger.LogDebug("File upload ticket for {path} expired!", path);
+
494 return;
+
495 }
+
496
+
497 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
+
498 {
+
499 if (!locked)
+
500 {
+
501 fileTicket.SetError(ErrorCode.ConfigurationContendedAccess, null);
+
502 return;
+
503 }
+
504
+
505 if (systemIdentity == null)
+
506 await Task.Factory.StartNew(WriteCallback, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
+
507 else
+
508 await systemIdentity.RunImpersonated(WriteCallback, cancellationToken);
+
509 }
+
510
+
511 if (!success)
+
512 fileTicket.SetError(ErrorCode.ConfigurationFileUpdated, fileHash);
+
513 else if (uploadStream.Length > 0)
+
514 postWriteHandler.HandleWrite(path);
+
515 }
+
516 }
+
517
+
518 result = new ConfigurationFileResponse
+
519 {
+
520 FileTicket = fileTicket.Ticket.FileTicket,
+
521 LastReadHash = previousHash,
+
522 IsDirectory = false,
+
523 AccessDenied = false,
+
524 Path = configurationRelativePath,
+
525 };
+
526
+
527 lock (disposeCts)
+
528 uploadTasks = Task.WhenAll(uploadTasks, UploadHandler());
+
529 }
+
530 catch (UnauthorizedAccessException)
+
531 {
+
532 // this happens on windows, dunno about linux
+
533 bool isDirectory;
+
534 try
+
535 {
+
536 isDirectory = synchronousIOManager.IsDirectory(path);
+
537 }
+
538 catch (Exception ex)
+
539 {
+
540 logger.LogDebug(ex, "IsDirectory exception!");
+
541 isDirectory = false;
+
542 }
+
543
+
544 result = new ConfigurationFileResponse
+
545 {
+
546 Path = configurationRelativePath,
+
547 };
+
548 if (!isDirectory)
+
549 result.AccessDenied = true;
+
550
+
551 result.IsDirectory = isDirectory;
+
552 }
+
553 }
+
554
+
555 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
+
556 {
+
557 if (!locked)
+
558 {
+
559 logger.LogDebug("Contention when attempting to write file!");
+
560 return null;
+
561 }
+
562
+
563 if (systemIdentity == null)
+
564 await Task.Factory.StartNew(WriteImpl, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
+
565 else
+
566 await systemIdentity.RunImpersonated(WriteImpl, cancellationToken);
+
567 }
+
568
+
569 return result;
+
570 }
+
571
+
573 public async Task<bool?> CreateDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
+
574 {
+
575 await EnsureDirectories(cancellationToken);
+
576 var path = ValidateConfigRelativePath(configurationRelativePath);
+
577
+
578 bool? result = null;
+
579 void DoCreate() => result = synchronousIOManager.CreateDirectory(path, cancellationToken);
+
580
+
581 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
+
582 {
+
583 if (!locked)
+
584 {
+
585 logger.LogDebug("Contention when attempting to create directory!");
+
586 return null;
+
587 }
+
588
+
589 if (systemIdentity == null)
+
590 await Task.Factory.StartNew(DoCreate, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
+
591 else
+
592 await systemIdentity.RunImpersonated(DoCreate, cancellationToken);
+
593 }
+
594
+
595 return result.Value;
+
596 }
+
597
+
599 public Task StartAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);
+
600
+
602 public Task StopAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);
+
603
+
605 public async Task HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
+
606 {
+
607 ArgumentNullException.ThrowIfNull(parameters);
608
-
609 if (!EventTypeScriptFileNameMap.TryGetValue(eventType, out var scriptName))
-
610 return;
-
611
-
612 // always execute in serial
-
613 using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken))
-
614 {
-
615 var files = await ioManager.GetFilesWithExtension(EventScriptsSubdirectory, platformIdentifier.ScriptFileExtension, false, cancellationToken);
-
616 var resolvedScriptsDir = ioManager.ResolvePath(EventScriptsSubdirectory);
-
617
-
618 var scriptFiles = files
-
619 .Select(x => ioManager.GetFileName(x))
-
620 .Where(x => x.StartsWith(scriptName, StringComparison.Ordinal))
-
621 .ToList();
-
622
-
623 if (!scriptFiles.Any())
-
624 {
-
625 logger.LogTrace("No event scripts starting with \"{scriptName}\" detected", scriptName);
-
626 return;
-
627 }
-
628
-
629 foreach (var scriptFile in scriptFiles)
-
630 {
-
631 logger.LogTrace("Running event script {scriptFile}...", scriptFile);
-
632 await using (var script = processExecutor.LaunchProcess(
-
633 ioManager.ConcatPath(resolvedScriptsDir, scriptFile),
-
634 resolvedScriptsDir,
-
635 String.Join(
-
636 ' ',
-
637 parameters.Select(arg =>
-
638 {
-
639 if (!arg.Contains(' ', StringComparison.Ordinal))
-
640 return arg;
-
641
-
642 arg = arg.Replace("\"", "\\\"", StringComparison.Ordinal);
+
609 await EnsureDirectories(cancellationToken);
+
610
+
611 if (!EventTypeScriptFileNameMap.TryGetValue(eventType, out var scriptName))
+
612 return;
+
613
+
614 // always execute in serial
+
615 using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken))
+
616 {
+
617 var files = await ioManager.GetFilesWithExtension(EventScriptsSubdirectory, platformIdentifier.ScriptFileExtension, false, cancellationToken);
+
618 var resolvedScriptsDir = ioManager.ResolvePath(EventScriptsSubdirectory);
+
619
+
620 var scriptFiles = files
+
621 .Select(x => ioManager.GetFileName(x))
+
622 .Where(x => x.StartsWith(scriptName, StringComparison.Ordinal))
+
623 .ToList();
+
624
+
625 if (!scriptFiles.Any())
+
626 {
+
627 logger.LogTrace("No event scripts starting with \"{scriptName}\" detected", scriptName);
+
628 return;
+
629 }
+
630
+
631 foreach (var scriptFile in scriptFiles)
+
632 {
+
633 logger.LogTrace("Running event script {scriptFile}...", scriptFile);
+
634 await using (var script = processExecutor.LaunchProcess(
+
635 ioManager.ConcatPath(resolvedScriptsDir, scriptFile),
+
636 resolvedScriptsDir,
+
637 String.Join(
+
638 ' ',
+
639 parameters.Select(arg =>
+
640 {
+
641 if (!arg.Contains(' ', StringComparison.Ordinal))
+
642 return arg;
643
-
644 return $"\"{arg}\"";
-
645 })),
-
646 readStandardHandles: true,
-
647 noShellExecute: true))
-
648 using (cancellationToken.Register(() => script.Terminate()))
-
649 {
-
650 if (sessionConfiguration.LowPriorityDeploymentProcesses)
-
651 script.AdjustPriority(false);
-
652
-
653 var exitCode = await script.Lifetime;
-
654 cancellationToken.ThrowIfCancellationRequested();
-
655 var scriptOutput = await script.GetCombinedOutput(cancellationToken);
-
656 if (exitCode != 0)
-
657 throw new JobException($"Script {scriptFile} exited with code {exitCode}:{Environment.NewLine}{scriptOutput}");
-
658 else
-
659 logger.LogDebug("Script output:{newLine}{scriptOutput}", Environment.NewLine, scriptOutput);
-
660 }
-
661 }
-
662 }
-
663 }
-
664
-
666 public async Task<bool?> DeleteDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
-
667 {
-
668 await EnsureDirectories(cancellationToken);
-
669 var path = ValidateConfigRelativePath(configurationRelativePath);
-
670
-
671 var result = false;
-
672 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
-
673 {
-
674 if (!locked)
-
675 {
-
676 logger.LogDebug("Contention when attempting to enumerate directory!");
-
677 return null;
-
678 }
-
679
-
680 void CheckDeleteImpl() => result = synchronousIOManager.DeleteDirectory(path);
+
644 arg = arg.Replace("\"", "\\\"", StringComparison.Ordinal);
+
645
+
646 return $"\"{arg}\"";
+
647 })),
+
648 readStandardHandles: true,
+
649 noShellExecute: true))
+
650 using (cancellationToken.Register(() => script.Terminate()))
+
651 {
+
652 if (sessionConfiguration.LowPriorityDeploymentProcesses)
+
653 script.AdjustPriority(false);
+
654
+
655 var exitCode = await script.Lifetime;
+
656 cancellationToken.ThrowIfCancellationRequested();
+
657 var scriptOutput = await script.GetCombinedOutput(cancellationToken);
+
658 if (exitCode != 0)
+
659 throw new JobException($"Script {scriptFile} exited with code {exitCode}:{Environment.NewLine}{scriptOutput}");
+
660 else
+
661 logger.LogDebug("Script output:{newLine}{scriptOutput}", Environment.NewLine, scriptOutput);
+
662 }
+
663 }
+
664 }
+
665 }
+
666
+
668 public async Task<bool?> DeleteDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
+
669 {
+
670 await EnsureDirectories(cancellationToken);
+
671 var path = ValidateConfigRelativePath(configurationRelativePath);
+
672
+
673 var result = false;
+
674 using (SemaphoreSlimContext.TryLock(semaphore, out var locked))
+
675 {
+
676 if (!locked)
+
677 {
+
678 logger.LogDebug("Contention when attempting to enumerate directory!");
+
679 return null;
+
680 }
681
-
682 if (systemIdentity != null)
-
683 await systemIdentity.RunImpersonated(CheckDeleteImpl, cancellationToken);
-
684 else
-
685 CheckDeleteImpl();
-
686 }
-
687
-
688 return result;
-
689 }
-
690
-
695 string StaticIgnorePath() => ioManager.ConcatPath(GameStaticFilesSubdirectory, StaticIgnoreFile);
-
696
-
702 async Task EnsureDirectories(CancellationToken cancellationToken)
-
703 {
-
704 async Task ValidateStaticFolder()
-
705 {
-
706 await ioManager.CreateDirectory(GameStaticFilesSubdirectory, cancellationToken);
-
707 var staticIgnorePath = StaticIgnorePath();
-
708 if (!await ioManager.FileExists(staticIgnorePath, cancellationToken))
-
709 await ioManager.WriteAllBytes(staticIgnorePath, Array.Empty<byte>(), cancellationToken);
-
710 }
-
711
-
712 async Task ValidateCodeModsFolder()
-
713 {
-
714 if (await ioManager.DirectoryExists(CodeModificationsSubdirectory, cancellationToken))
-
715 return;
-
716
-
717 await ioManager.CreateDirectory(CodeModificationsSubdirectory, cancellationToken);
-
718 await Task.WhenAll(
-
719 ioManager.WriteAllBytes(
-
720 ioManager.ConcatPath(
-
721 CodeModificationsSubdirectory,
-
722 CodeModificationsHeadFile),
-
723 Encoding.UTF8.GetBytes(DefaultHeadInclude),
-
724 cancellationToken),
-
725 ioManager.WriteAllBytes(
-
726 ioManager.ConcatPath(
-
727 CodeModificationsSubdirectory,
-
728 CodeModificationsTailFile),
-
729 Encoding.UTF8.GetBytes(DefaultTailInclude),
-
730 cancellationToken));
-
731 }
-
732
-
733 await Task.WhenAll(
-
734 ValidateCodeModsFolder(),
-
735 ioManager.CreateDirectory(EventScriptsSubdirectory, cancellationToken),
-
736 ValidateStaticFolder());
-
737 }
-
738
-
744 string ValidateConfigRelativePath(string configurationRelativePath)
-
745 {
-
746 var nullOrEmptyCheck = String.IsNullOrEmpty(configurationRelativePath);
-
747 if (nullOrEmptyCheck)
-
748 configurationRelativePath = DefaultIOManager.CurrentDirectory;
-
749 if (configurationRelativePath[0] == Path.DirectorySeparatorChar || configurationRelativePath[0] == Path.AltDirectorySeparatorChar)
-
750 configurationRelativePath = DefaultIOManager.CurrentDirectory + configurationRelativePath;
-
751 var resolved = ioManager.ResolvePath(configurationRelativePath);
-
752 var local = !nullOrEmptyCheck ? ioManager.ResolvePath() : null;
-
753 if (!nullOrEmptyCheck && resolved.Length < local.Length) // .. fuccbois
-
754 throw new InvalidOperationException("Attempted to access file outside of configuration manager!");
-
755 return resolved;
-
756 }
-
757 }
-
758}
+
682 void CheckDeleteImpl() => result = synchronousIOManager.DeleteDirectory(path);
+
683
+
684 if (systemIdentity != null)
+
685 await systemIdentity.RunImpersonated(CheckDeleteImpl, cancellationToken);
+
686 else
+
687 CheckDeleteImpl();
+
688 }
+
689
+
690 return result;
+
691 }
+
692
+
697 string StaticIgnorePath() => ioManager.ConcatPath(GameStaticFilesSubdirectory, StaticIgnoreFile);
+
698
+
704 async Task EnsureDirectories(CancellationToken cancellationToken)
+
705 {
+
706 async Task ValidateStaticFolder()
+
707 {
+
708 await ioManager.CreateDirectory(GameStaticFilesSubdirectory, cancellationToken);
+
709 var staticIgnorePath = StaticIgnorePath();
+
710 if (!await ioManager.FileExists(staticIgnorePath, cancellationToken))
+
711 await ioManager.WriteAllBytes(staticIgnorePath, Array.Empty<byte>(), cancellationToken);
+
712 }
+
713
+
714 async Task ValidateCodeModsFolder()
+
715 {
+
716 if (await ioManager.DirectoryExists(CodeModificationsSubdirectory, cancellationToken))
+
717 return;
+
718
+
719 await ioManager.CreateDirectory(CodeModificationsSubdirectory, cancellationToken);
+
720 await Task.WhenAll(
+
721 ioManager.WriteAllBytes(
+
722 ioManager.ConcatPath(
+
723 CodeModificationsSubdirectory,
+
724 CodeModificationsHeadFile),
+
725 Encoding.UTF8.GetBytes(DefaultHeadInclude),
+
726 cancellationToken),
+
727 ioManager.WriteAllBytes(
+
728 ioManager.ConcatPath(
+
729 CodeModificationsSubdirectory,
+
730 CodeModificationsTailFile),
+
731 Encoding.UTF8.GetBytes(DefaultTailInclude),
+
732 cancellationToken));
+
733 }
+
734
+
735 await Task.WhenAll(
+
736 ValidateCodeModsFolder(),
+
737 ioManager.CreateDirectory(EventScriptsSubdirectory, cancellationToken),
+
738 ValidateStaticFolder());
+
739 }
+
740
+
746 string ValidateConfigRelativePath(string configurationRelativePath)
+
747 {
+
748 var nullOrEmptyCheck = String.IsNullOrEmpty(configurationRelativePath);
+
749 if (nullOrEmptyCheck)
+
750 configurationRelativePath = DefaultIOManager.CurrentDirectory;
+
751 if (configurationRelativePath[0] == Path.DirectorySeparatorChar || configurationRelativePath[0] == Path.AltDirectorySeparatorChar)
+
752 configurationRelativePath = DefaultIOManager.CurrentDirectory + configurationRelativePath;
+
753 var resolved = ioManager.ResolvePath(configurationRelativePath);
+
754 var local = !nullOrEmptyCheck ? ioManager.ResolvePath() : null;
+
755 if (!nullOrEmptyCheck && resolved.Length < local.Length) // .. fuccbois
+
756 throw new InvalidOperationException("Attempted to access file outside of configuration manager!");
+
757 return resolved;
+
758 }
+
759 }
+
760}
Tgstation.Server.Api.Models.Response.ConfigurationFileResponse
Response when reading configuration files.
Definition: ConfigurationFileResponse.cs:7
Tgstation.Server.Api.Models.Response.FileTicketResponse.FileTicket
virtual ? string FileTicket
The ticket to use to access the Routes.Transfer controller.
Definition: FileTicketResponse.cs:11
Tgstation.Server.Host.Components.Events.EventScriptAttribute
Attribute for indicating the script that a given EventType runs.
Definition: EventScriptAttribute.cs:10
Tgstation.Server.Host.Components.Events.EventScriptAttribute.ScriptName
string ScriptName
The name of the script the event script the EventType runs.
Definition: EventScriptAttribute.cs:14
Tgstation.Server.Host.Components.StaticFiles.Configuration
Definition: Configuration.cs:29
Tgstation.Server.Host.Components.StaticFiles.Configuration.processExecutor
readonly IProcessExecutor processExecutor
The IProcessExecutor for Configuration.
Definition: Configuration.cs:104
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.DeleteDirectory
async Task< bool?> DeleteDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Attempt to delete an empty directory at configurationRelativePath . true if the directory was empty a...
Definition: Configuration.cs:666
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.DeleteDirectory
async Task< bool?> DeleteDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Attempt to delete an empty directory at configurationRelativePath . true if the directory was empty a...
Definition: Configuration.cs:668
Tgstation.Server.Host.Components.StaticFiles.Configuration.fileTransferService
readonly IFileTransferTicketProvider fileTransferService
The IFileTransferTicketProvider for Configuration.
Definition: Configuration.cs:119
Tgstation.Server.Host.Components.StaticFiles.Configuration.DefaultTailInclude
static readonly string DefaultTailInclude
Default contents of CodeModificationsHeadFile.
Definition: Configuration.cs:68
Tgstation.Server.Host.Components.StaticFiles.Configuration.synchronousIOManager
readonly ISynchronousIOManager synchronousIOManager
The ISynchronousIOManager for Configuration.
Definition: Configuration.cs:94
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.ListDirectory
async Task< IReadOnlyList< ConfigurationFileResponse > > ListDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Get ConfigurationFileResponses for all items in a given configurationRelativePath ....
Definition: Configuration.cs:237
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.ListDirectory
async Task< IReadOnlyList< ConfigurationFileResponse > > ListDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Get ConfigurationFileResponses for all items in a given configurationRelativePath ....
Definition: Configuration.cs:239
Tgstation.Server.Host.Components.StaticFiles.Configuration.StopAsync
Task StopAsync(CancellationToken cancellationToken)
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.ValidateConfigRelativePath
string ValidateConfigRelativePath(string configurationRelativePath)
Resolve a given configurationRelativePath to it's full path or throw an InvalidOperationException if...
Definition: Configuration.cs:744
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.ValidateConfigRelativePath
string ValidateConfigRelativePath(string configurationRelativePath)
Resolve a given configurationRelativePath to it's full path or throw an InvalidOperationException if...
Definition: Configuration.cs:746
Tgstation.Server.Host.Components.StaticFiles.Configuration.CopyDMFilesTo
async Task< ServerSideModifications > CopyDMFilesTo(string dmeFile, string destination, CancellationToken cancellationToken)
Copies all files in the CodeModifications directory to destination . A Task<TResult> resulting in the...
Definition: Configuration.cs:201
Tgstation.Server.Host.Components.StaticFiles.Configuration.StaticIgnoreFile
const string StaticIgnoreFile
Name of the ignore file in GameStaticFilesSubdirectory.
Definition: Configuration.cs:48
Tgstation.Server.Host.Components.StaticFiles.Configuration.sessionConfiguration
readonly SessionConfiguration sessionConfiguration
The SessionConfiguration for Configuration.
Definition: Configuration.cs:134
Tgstation.Server.Host.Components.StaticFiles.Configuration.Dispose
void Dispose()
Definition: Configuration.cs:193
Tgstation.Server.Host.Components.StaticFiles.Configuration.StaticIgnorePath
string StaticIgnorePath()
Get the proper path to StaticIgnoreFile.
Tgstation.Server.Host.Components.StaticFiles.Configuration.Configuration
Configuration(IIOManager ioManager, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, IPlatformIdentifier platformIdentifier, IFileTransferTicketProvider fileTransferService, ILogger< Configuration > logger, GeneralConfiguration generalConfiguration, SessionConfiguration sessionConfiguration)
Initializes a new instance of the Configuration class.
Definition: Configuration.cs:164
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.Write
async Task< ConfigurationFileResponse > Write(string configurationRelativePath, ISystemIdentity systemIdentity, string previousHash, CancellationToken cancellationToken)
Writes to a given configurationRelativePath . A Task<TResult> resulting in the updated ConfigurationF...
Definition: Configuration.cs:461
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.Write
async Task< ConfigurationFileResponse > Write(string configurationRelativePath, ISystemIdentity systemIdentity, string previousHash, CancellationToken cancellationToken)
Writes to a given configurationRelativePath . A Task<TResult> resulting in the updated ConfigurationF...
Definition: Configuration.cs:463
Tgstation.Server.Host.Components.StaticFiles.Configuration.EventTypeScriptFileNameMap
static readonly IReadOnlyDictionary< EventType, string > EventTypeScriptFileNameMap
Map of EventTypes to the filename of the event scripts they trigger.
Definition: Configuration.cs:73
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.EnsureDirectories
async Task EnsureDirectories(CancellationToken cancellationToken)
Ensures standard configuration directories exist.
Definition: Configuration.cs:702
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.EnsureDirectories
async Task EnsureDirectories(CancellationToken cancellationToken)
Ensures standard configuration directories exist.
Definition: Configuration.cs:704
Tgstation.Server.Host.Components.StaticFiles.Configuration.symlinkFactory
readonly ISymlinkFactory symlinkFactory
The ISymlinkFactory for Configuration.
Definition: Configuration.cs:99
Tgstation.Server.Host.Components.StaticFiles.Configuration.disposeCts
readonly CancellationTokenSource disposeCts
The CancellationTokenSource that is triggered when IDisposable.Dispose is called.
Definition: Configuration.cs:144
Tgstation.Server.Host.Components.StaticFiles.Configuration.uploadTasks
Task uploadTasks
The culmination of all upload file transfer callbacks.
Definition: Configuration.cs:149
Tgstation.Server.Host.Components.StaticFiles.Configuration.CodeModificationsSubdirectory
const string CodeModificationsSubdirectory
The CodeModifications directory name.
Definition: Configuration.cs:33
Tgstation.Server.Host.Components.StaticFiles.Configuration.postWriteHandler
readonly IPostWriteHandler postWriteHandler
The IPostWriteHandler for Configuration.
Definition: Configuration.cs:109
Tgstation.Server.Host.Components.StaticFiles.Configuration.platformIdentifier
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for Configuration.
Definition: Configuration.cs:114
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.Read
async Task< ConfigurationFileResponse > Read(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Reads a given configurationRelativePath . A Task<TResult> resulting in the ConfigurationFileResponse ...
Definition: Configuration.cs:281
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.Read
async Task< ConfigurationFileResponse > Read(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Reads a given configurationRelativePath . A Task<TResult> resulting in the ConfigurationFileResponse ...
Definition: Configuration.cs:283
Tgstation.Server.Host.Components.StaticFiles.Configuration.CodeModificationsHeadFile
const string CodeModificationsHeadFile
The HeadInclude.dm filename.
Definition: Configuration.cs:53
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.HandleEvent
async Task HandleEvent(EventType eventType, IEnumerable< string > parameters, bool deploymentPipeline, CancellationToken cancellationToken)
Handle a given eventType . A Task representing the running operation.
Definition: Configuration.cs:603
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.HandleEvent
async Task HandleEvent(EventType eventType, IEnumerable< string > parameters, bool deploymentPipeline, CancellationToken cancellationToken)
Handle a given eventType . A Task representing the running operation.
Definition: Configuration.cs:605
Tgstation.Server.Host.Components.StaticFiles.Configuration.logger
readonly ILogger< Configuration > logger
The ILogger for Configuration.
Definition: Configuration.cs:124
Tgstation.Server.Host.Components.StaticFiles.Configuration.generalConfiguration
readonly GeneralConfiguration generalConfiguration
The GeneralConfiguration for Configuration.
Definition: Configuration.cs:129
Tgstation.Server.Host.Components.StaticFiles.Configuration.CodeModificationsTailFile
const string CodeModificationsTailFile
The TailInclude.dm filename.
Definition: Configuration.cs:58
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.CreateDirectory
async Task< bool?> CreateDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Create an empty directory at configurationRelativePath . A Task<TResult> resulting in true if the dir...
Definition: Configuration.cs:571
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.CreateDirectory
async Task< bool?> CreateDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
Create an empty directory at configurationRelativePath . A Task<TResult> resulting in true if the dir...
Definition: Configuration.cs:573
Tgstation.Server.Host.Components.StaticFiles.Configuration.DefaultHeadInclude
static readonly string DefaultHeadInclude
Default contents of CodeModificationsHeadFile.
Definition: Configuration.cs:63
Tgstation.Server.Host.Components.StaticFiles.Configuration.GameStaticFilesSubdirectory
const string GameStaticFilesSubdirectory
The GameStaticFiles directory name.
Definition: Configuration.cs:43
Tgstation.Server.Host.Components.StaticFiles.Configuration.StartAsync
Task StartAsync(CancellationToken cancellationToken)
Tgstation.Server.Host.Components.StaticFiles.Configuration.EventScriptsSubdirectory
const string EventScriptsSubdirectory
The EventScripts directory name.
Definition: Configuration.cs:38
Tgstation.Server.Host.Components.StaticFiles.Configuration.semaphore
readonly SemaphoreSlim semaphore
The SemaphoreSlim for Configuration. Also used as a lock object.
Definition: Configuration.cs:139
-
Tgstation.Server.Host.Components.StaticFiles.Configuration.SymlinkStaticFilesTo
async Task SymlinkStaticFilesTo(string destination, CancellationToken cancellationToken)
Symlinks all directories in the GameData directory to destination . A Task representing the running o...
Definition: Configuration.cs:391
+
Tgstation.Server.Host.Components.StaticFiles.Configuration.SymlinkStaticFilesTo
async Task SymlinkStaticFilesTo(string destination, CancellationToken cancellationToken)
Symlinks all directories in the GameData directory to destination . A Task representing the running o...
Definition: Configuration.cs:393
Tgstation.Server.Host.Components.StaticFiles.Configuration.ioManager
readonly IIOManager ioManager
The IIOManager for Configuration.
Definition: Configuration.cs:89
Tgstation.Server.Host.Components.StaticFiles.ServerSideModifications
Represents code modifications via configuration.
Definition: ServerSideModifications.cs:7
Tgstation.Server.Host.Configuration.GeneralConfiguration
General configuration options.
Definition: GeneralConfiguration.cs:18
diff --git a/_tgstation_8_server_8_host_8_service_2_program_8cs.html b/_tgstation_8_server_8_host_8_service_2_program_8cs.html index f031a571041..2ba4d5baa08 100644 --- a/_tgstation_8_server_8_host_8_service_2_program_8cs.html +++ b/_tgstation_8_server_8_host_8_service_2_program_8cs.html @@ -77,7 +77,9 @@
Classes | -Namespaces
+Namespaces | +Functions | +Variables
Program.cs File Reference
@@ -100,7 +102,202 @@   namespace  Tgstation.Server.Host.Service   + + + + + + + + + + + + + +

+Functions

 Tgstation.Server.Host.Service.InvokeSC (null)
 
void RestartService (ServiceController serviceController)
 Restarts a service using a given serviceController . More...
 
async Task RunConfigure (CancellationToken cancellationToken)
 Runs the host application with the setup wizard. More...
 
string[] GetPassthroughArgs ()
 Format PassthroughArgs into an Array. More...
 
+ + +

+Variables

return Tgstation.Server.Host.Service.serviceStopped
 
+

Function Documentation

+ +

◆ GetPassthroughArgs()

+ +
+
+ + + + + + + +
string[] GetPassthroughArgs ()
+
+ +

Format PassthroughArgs into an Array.

+
Returns
PassthroughArgs formatted as a string Array.
+ +

Referenced by Tgstation.Server.Host.Service.Program.OnExecuteAsync(), and RunConfigure().

+
+Here is the caller graph for this function:
+
+
+ + + + + +
+ +
+
+ +

◆ RestartService()

+ +
+
+ + + + + + + + +
void RestartService (ServiceController serviceController)
+
+ +

Restarts a service using a given serviceController .

+
Parameters
+ + +
serviceControllerThe ServiceController for the service to restart.
+
+
+ +

Definition at line 255 of file Program.cs.

+
256 {
+
257 if (serviceController.Status != ServiceControllerStatus.Running)
+
258 return;
+
259
+
260 var stop = !Detach;
+
261 if (!stop)
+
262 {
+
263 serviceController.ExecuteCommand(
+ + +
266 .Value);
+
267 serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
+
268 if (serviceController.Status != ServiceControllerStatus.Stopped)
+
269 stop = true;
+
270 }
+
271
+
272 if (stop)
+
273 {
+
274 serviceController.Stop();
+
275 serviceController.WaitForStatus(ServiceControllerStatus.Stopped);
+
276 }
+
277 }
+
Values able to be passed via the update file path.
Definition: PipeCommands.cs:7
+
static ? int GetCommandId(string command)
Gets the int value of a given command .
+
const string CommandDetachingShutdown
Stops the server ASAP, detaching the watchdog for any running instances.
Definition: PipeCommands.cs:21
+
+

References Tgstation.Server.Host.Common.PipeCommands.CommandDetachingShutdown, and Tgstation.Server.Host.Common.PipeCommands.GetCommandId().

+ +

Referenced by Tgstation.Server.Host.Service.Program.InvokeSC(), and Tgstation.Server.Host.Service.Program.OnExecuteAsync().

+
+Here is the call graph for this function:
+
+
+ + + + +
+
+Here is the caller graph for this function:
+
+
+ + + + + +
+ +
+
+ +

◆ RunConfigure()

+ +
+
+ + + + + + + + +
async Task RunConfigure (CancellationToken cancellationToken)
+
+ +

Runs the host application with the setup wizard.

+
Parameters
+ + +
cancellationTokenThe CancellationToken for the operation.
+
+
+
Returns
A Task representing the running operation.
+ +

Definition at line 284 of file Program.cs.

+
285 {
+
286 using var loggerFactory = LoggerFactory.Create(builder =>
+
287 {
+
288 if (!Silent)
+
289 builder.AddConsole();
+
290 });
+
291
+
292 var watchdog = WatchdogFactory.CreateWatchdog(new NoopSignalChecker(), loggerFactory);
+
293 await watchdog.RunAsync(true, GetPassthroughArgs(), cancellationToken);
+
294 }
+
string[] GetPassthroughArgs()
Format PassthroughArgs into an Array.
+ +
IWatchdog CreateWatchdog(ISignalChecker signalChecker, ILoggerFactory loggerFactory)
Create a IWatchdog. A new IWatchdog.
+
Task< bool > RunAsync(bool runConfigure, string[] args, CancellationToken cancellationToken)
Run the IWatchdog.
+
+

References Tgstation.Server.Host.Watchdog.WatchdogFactory.CreateWatchdog(), GetPassthroughArgs(), and Tgstation.Server.Host.Watchdog.IWatchdog.RunAsync().

+ +

Referenced by Tgstation.Server.Host.Service.Program.OnExecuteAsync().

+
+Here is the call graph for this function:
+
+
+ + + + + + +
+
+Here is the caller graph for this function:
+
+
+ + + + +
+ +
+