@@ -21,12 +21,26 @@ import * as file from '../infrastructure/file';
2121import * as logging from '../infrastructure/logging' ;
2222import { ShadowsocksAccessKey , ShadowsocksServer } from '../model/shadowsocks_server' ;
2323
24+ /** Represents an outline-ss-server configuration with multiple services. */
25+ export interface OutlineSSServerConfig {
26+ services : {
27+ listeners : {
28+ type : string ;
29+ address : string ;
30+ } [ ] ;
31+ keys : {
32+ id : string ;
33+ cipher : string ;
34+ secret : string ;
35+ } [ ] ;
36+ } [ ] ;
37+ }
38+
2439// Runs outline-ss-server.
2540export class OutlineShadowsocksServer implements ShadowsocksServer {
2641 private ssProcess : child_process . ChildProcess ;
2742 private ipCountryFilename ?: string ;
2843 private ipAsnFilename ?: string ;
29- private isAsnMetricsEnabled = false ;
3044 private isReplayProtectionEnabled = false ;
3145
3246 /**
@@ -81,22 +95,39 @@ export class OutlineShadowsocksServer implements ShadowsocksServer {
8195
8296 private writeConfigFile ( keys : ShadowsocksAccessKey [ ] ) : Promise < void > {
8397 return new Promise ( ( resolve , reject ) => {
84- const keysJson = { keys : [ ] as ShadowsocksAccessKey [ ] } ;
85- for ( const key of keys ) {
98+ const validKeys : ShadowsocksAccessKey [ ] = keys . filter ( ( key ) => {
8699 if ( ! isAeadCipher ( key . cipher ) ) {
87100 logging . error (
88101 `Cipher ${ key . cipher } for access key ${ key . id } is not supported: use an AEAD cipher instead.`
89102 ) ;
90- continue ;
103+ return false ;
91104 }
105+ return true ;
106+ } ) ;
92107
93- keysJson . keys . push ( key ) ;
108+ const config : OutlineSSServerConfig = { services : [ ] } ;
109+ const keysByPort : Record < number , ShadowsocksAccessKey [ ] > = { } ;
110+ for ( const key of validKeys ) {
111+ ( keysByPort [ key . port ] ??= [ ] ) . push ( key ) ;
112+ }
113+ for ( const port in keysByPort ) {
114+ const service = {
115+ listeners : [
116+ { type : 'tcp' , address : `[::]:${ port } ` } ,
117+ { type : 'udp' , address : `[::]:${ port } ` } ,
118+ ] ,
119+ keys : keysByPort [ port ] . map ( ( key ) => ( {
120+ id : key . id ,
121+ cipher : key . cipher ,
122+ secret : key . secret ,
123+ } ) ) ,
124+ } ;
125+ config . services . push ( service ) ;
94126 }
95127
96128 mkdirp . sync ( path . dirname ( this . configFilename ) ) ;
97-
98129 try {
99- file . atomicWriteFileSync ( this . configFilename , jsyaml . safeDump ( keysJson , { sortKeys : true } ) ) ;
130+ file . atomicWriteFileSync ( this . configFilename , jsyaml . safeDump ( config , { sortKeys : true } ) ) ;
100131 resolve ( ) ;
101132 } catch ( error ) {
102133 reject ( error ) ;
0 commit comments