mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Add iOS app skeleton
This commit is contained in:
parent
90c0df5c5d
commit
573257f1a8
@ -6,14 +6,13 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ReSwift
|
||||
|
||||
struct App {
|
||||
static let store = Store<AppState>(reducer: appReducer, state: nil)
|
||||
static let trackTimer = TrackTimer()
|
||||
static let userNotificationsController = UserNotificationsController()
|
||||
static let mpdServerController = MPDServerController()
|
||||
static let mpdServerDelegate = MPDServerDelegate()
|
||||
static let mpdServerController = MPDServerController(delegate: mpdServerDelegate)
|
||||
static var mpdClient: MPDClient!
|
||||
}
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
//
|
||||
// ArtistListActions.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/9/29.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import ReSwift
|
||||
|
||||
struct UpdateArtistListAction: Action {
|
||||
var artists: [String]
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
//
|
||||
// ArtistListState.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/9/20.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import ReSwift
|
||||
|
||||
struct ArtistListState: StateType, Equatable {
|
||||
var artists: [Artist] = []
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
//
|
||||
// ArtistReducer.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/9/29.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import ReSwift
|
||||
|
||||
func artistListReducer(action: Action, state: ArtistListState?) -> ArtistListState {
|
||||
var state = state ?? ArtistListState()
|
||||
|
||||
switch action {
|
||||
case let action as UpdateArtistListAction:
|
||||
state.artists = action.artists.map { Artist(name: $0) }
|
||||
|
||||
default:
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,11 @@
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>Persephone-iOS.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>Persephone.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
@ -14,6 +19,11 @@
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>libmpdclient.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
|
||||
@ -10,8 +10,8 @@ import Foundation
|
||||
import ReSwift
|
||||
|
||||
class MPDServerController {
|
||||
init() {
|
||||
App.mpdClient = MPDClient(withDelegate: App.mpdServerDelegate)
|
||||
init(delegate: MPDClientDelegate? = nil) {
|
||||
App.mpdClient = MPDClient(withDelegate: delegate)
|
||||
|
||||
App.store.subscribe(self) {
|
||||
$0.select { $0.preferencesState.mpdServer }
|
||||
@ -6,7 +6,8 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Dispatch
|
||||
import NotificationCenter
|
||||
|
||||
class MPDServerDelegate: MPDClientDelegate {
|
||||
func didConnect(mpdClient: MPDClient) {
|
||||
@ -67,8 +68,5 @@ class MPDServerDelegate: MPDClientDelegate {
|
||||
}
|
||||
|
||||
func didLoadArtists(mpdClient: MPDClient, artists: [String]) {
|
||||
DispatchQueue.main.async {
|
||||
App.store.dispatch(UpdateArtistListAction(artists: artists))
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Shared/Lib/MachTime.swift
Normal file
18
Shared/Lib/MachTime.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// MachTime.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2020-3-19.
|
||||
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
func machTime() -> UInt64 {
|
||||
var info = mach_timebase_info()
|
||||
mach_timebase_info(&info)
|
||||
|
||||
return mach_absolute_time() * UInt64(info.numer) / UInt64(info.denom)
|
||||
}
|
||||
|
||||
func machTimeS() -> Double {
|
||||
return Double(machTime()) / 1_000_000_000
|
||||
}
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import CryptoSwift
|
||||
|
||||
struct Album {
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
//
|
||||
// Artist.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/10/04.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
struct Artist {
|
||||
var name: String
|
||||
var image: Loading<NSImage?> = .notLoaded
|
||||
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
|
||||
extension Artist: Equatable {
|
||||
static func == (lhs: Artist, rhs: Artist) -> Bool {
|
||||
return lhs.name == rhs.name
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import CryptoSwift
|
||||
|
||||
struct DraggedAlbum: Codable {
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum Loading<T> {
|
||||
case notLoaded
|
||||
case loading
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct MPDServer {
|
||||
let hostDefault = "127.0.0.1"
|
||||
let portDefault = 6600
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
struct QueueItem: Hashable {
|
||||
var song: Song
|
||||
var queuePos: Int
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Song {
|
||||
var mpdSong: MPDClient.MPDSong
|
||||
|
||||
|
||||
@ -6,17 +6,17 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Foundation
|
||||
|
||||
class TrackTimer: NSObject {
|
||||
class TrackTimer {
|
||||
var timer: Timer?
|
||||
var startTime: CFTimeInterval = CACurrentMediaTime()
|
||||
var startTime: CFTimeInterval = CFTimeInterval(machTimeS())
|
||||
var startElapsed: Double = 0
|
||||
|
||||
func start(elapsedTimeMs: UInt?) {
|
||||
guard let elapsedTimeMs = elapsedTimeMs else { return }
|
||||
|
||||
startTime = CACurrentMediaTime()
|
||||
startTime = CFTimeInterval(machTimeS())
|
||||
startElapsed = Double(elapsedTimeMs) / 1000
|
||||
|
||||
DispatchQueue.main.async {
|
||||
@ -26,7 +26,7 @@ class TrackTimer: NSObject {
|
||||
withTimeInterval: 0.25,
|
||||
repeats: true
|
||||
) { _ in
|
||||
let currentTime = CACurrentMediaTime()
|
||||
let currentTime = CFTimeInterval(machTimeS())
|
||||
|
||||
let timeDiff = currentTime - self.startTime
|
||||
let newElapsedTimeMs = UInt((self.startElapsed + timeDiff) * 1000)
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import ReSwift
|
||||
|
||||
struct UpdateAlbumListAction: Action {
|
||||
@ -13,7 +13,6 @@ struct AppState: StateType {
|
||||
var playerState = PlayerState()
|
||||
var queueState = QueueState()
|
||||
var albumListState = AlbumListState()
|
||||
var artistListState = ArtistListState()
|
||||
var preferencesState = PreferencesState()
|
||||
var uiState = UIState()
|
||||
}
|
||||
@ -14,7 +14,6 @@ func appReducer(action: Action, state: AppState?) -> AppState {
|
||||
playerState: playerReducer(action: action, state: state?.playerState),
|
||||
queueState: queueReducer(action: action, state: state?.queueState),
|
||||
albumListState: albumListReducer(action: action, state: state?.albumListState),
|
||||
artistListState: artistListReducer(action: action, state: state?.artistListState),
|
||||
preferencesState: preferencesReducer(action: action, state: state?.preferencesState),
|
||||
uiState: uiReducer(action: action, state: state?.uiState)
|
||||
)
|
||||
@ -6,7 +6,7 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Dispatch
|
||||
import ReSwift
|
||||
|
||||
func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
|
||||
@ -6,7 +6,7 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Dispatch
|
||||
import ReSwift
|
||||
|
||||
func queueReducer(action: Action, state: QueueState?) -> QueueState {
|
||||
@ -6,7 +6,7 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Dispatch
|
||||
import ReSwift
|
||||
|
||||
func uiReducer(action: Action, state: UIState?) -> UIState {
|
||||
@ -1,10 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
brew install meson
|
||||
|
||||
git submodule update --init
|
||||
|
||||
cd libmpdclient && \
|
||||
meson . output && \
|
||||
ninja -C output
|
||||
cd ..
|
||||
git apply --directory=libmpdclient/ libmpdclient.patch
|
||||
|
||||
18
iOS/App.swift
Normal file
18
iOS/App.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// App.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/4/30.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import ReSwift
|
||||
|
||||
struct App {
|
||||
static let store = Store<AppState>(reducer: appReducer, state: nil)
|
||||
static let trackTimer = TrackTimer()
|
||||
//static let userNotificationsController = UserNotificationsController()
|
||||
static let mpdServerDelegate = MPDServerDelegate()
|
||||
static let mpdServerController = MPDServerController(delegate: mpdServerDelegate)
|
||||
static var mpdClient: MPDClient!
|
||||
}
|
||||
30
iOS/AppDelegate.swift
Normal file
30
iOS/AppDelegate.swift
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// Persephone-iOS
|
||||
//
|
||||
// Created by Daniel Barber on 2020-3-13.
|
||||
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: UISceneSession Lifecycle
|
||||
|
||||
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
// Called when a new scene session is being created.
|
||||
// Use this method to select a configuration to create the new scene with.
|
||||
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
|
||||
// Called when the user discards a scene session.
|
||||
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
|
||||
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
|
||||
}
|
||||
}
|
||||
62
iOS/Info.plist
Normal file
62
iOS/Info.plist
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
22
iOSTests/Info.plist
Normal file
22
iOSTests/Info.plist
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
34
iOSTests/Persephone_iOSTests.swift
Normal file
34
iOSTests/Persephone_iOSTests.swift
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// Persephone_iOSTests.swift
|
||||
// Persephone-iOSTests
|
||||
//
|
||||
// Created by Daniel Barber on 2020-3-13.
|
||||
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Persephone_iOS
|
||||
|
||||
class Persephone_iOSTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
22
iOSUITests/Info.plist
Normal file
22
iOSUITests/Info.plist
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
43
iOSUITests/Persephone_iOSUITests.swift
Normal file
43
iOSUITests/Persephone_iOSUITests.swift
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// Persephone_iOSUITests.swift
|
||||
// Persephone-iOSUITests
|
||||
//
|
||||
// Created by Daniel Barber on 2020-3-13.
|
||||
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class Persephone_iOSUITests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||
continueAfterFailure = false
|
||||
|
||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// UI tests must launch the application that they test.
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Use recording to get started writing UI tests.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testLaunchPerformance() {
|
||||
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
|
||||
// This measures how long it takes to launch your application.
|
||||
measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) {
|
||||
XCUIApplication().launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
libmpdclient.patch
Normal file
24
libmpdclient.patch
Normal file
@ -0,0 +1,24 @@
|
||||
diff --git a/src/socket.c b/src/socket.c
|
||||
index 8f684b2..65498f2 100644
|
||||
--- a/src/socket.c
|
||||
+++ b/src/socket.c
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
+#include <sys/time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
diff --git a/src/sync.c b/src/sync.c
|
||||
index 3fefffe..ab96fb7 100644
|
||||
--- a/src/sync.c
|
||||
+++ b/src/sync.c
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
+#include <sys/time.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/select.h>
|
||||
Loading…
Reference in New Issue
Block a user